1"use strict";(self.webpackChunklayotto_docusaurus=self.webpackChunklayotto_docusaurus||[]).push([[1367],{1960:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var r=n(4848),o=n(8453);const a={},i="Observability (Tracing, Metrics)",s={id:"start/trace/trace",title:"Observability (Tracing, Metrics)",description:"1. Tracing",source:"@site/i18n/en-US/docusaurus-plugin-content-docs/current/start/trace/trace.md",sourceDirName:"start/trace",slug:"/start/trace/",permalink:"/layotto/en-US/docs/start/trace/",draft:!1,unlisted:!1,editUrl:"https://github.com/mosn/layotto/edit/main/docs/i18n/en-US/docusaurus-plugin-content-docs/current/start/trace/trace.md",tags:[],version:"current",frontMatter:{},sidebar:"mySidebar",previous:{title:"Use Layotto Actuator for health check and metadata query",permalink:"/layotto/en-US/docs/start/actuator/start"},next:{title:"Skywalking trace",permalink:"/layotto/en-US/docs/start/trace/skywalking"}},c={},l=[{value:"1. Tracing",id:"1-tracing",level:2},{value:"Features",id:"features",level:3},{value:"Configuration parameter description",id:"configuration-parameter-description",level:3},{value:"Trace mechanism",id:"trace-mechanism",level:3},{value:"More details about the tracing framework",id:"more-details-about-the-tracing-framework",level:3},{value:"Span structure:",id:"span-structure",level:4},{value:"generator interface:",id:"generator-interface",level:4},{value:"Exporter interface:",id:"exporter-interface",level:4},{value:"Span context transfer:",id:"span-context-transfer",level:4},{value:"Layotto side",id:"layotto-side",level:5},{value:"Component side",id:"component-side",level:5},{value:"2. Metrics",id:"2-metrics",level:2}];function d(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",img:"img",li:"li",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"observability-tracing-metrics",children:"Observability (Tracing, Metrics)"}),"\n",(0,r.jsx)(t.h2,{id:"1-tracing",children:"1. Tracing"}),"\n",(0,r.jsx)(t.h3,{id:"features",children:"Features"}),"\n",(0,r.jsxs)(t.p,{children:["In ",(0,r.jsx)(t.a,{href:"https://github.com/mosn/layotto/blob/main/configs/config_standalone.json",children:"config_standalone.json"}),", there is a paragraph about trace configuration as follows:"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-json",children:'[\n "tracing": {\n "enable": true,\n "driver": "SOFATracer",\n "config": {\n "generator": "mosntracing",\n "exporter": ["stdout"]\n }\n }\n]\n'})}),"\n",(0,r.jsx)(t.p,{children:"This configuration can turn on the trace capability of layotto, allowing layotto to print the tracing log after receiving the request. The user can specify the way of exporting the trace log and generating fields such as spanId and traceId through configuration."}),"\n",(0,r.jsx)(t.p,{children:"You can start a layotto server as follows:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Build"}),"\n"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-shell",children:"cd cmd/layotto_multiple_api/\n"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-shell",metastring:"@if.not.exist layotto",children:"# build it\ngo build -o layotto\n"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:"Run it"}),"\n"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-shell",metastring:"@background",children:"./layotto start -c ../../configs/config_standalone.json\n"})}),"\n",(0,r.jsxs)(t.p,{children:["The corresponding client demo is in ",(0,r.jsx)(t.a,{href:"https://github.com/mosn/layotto/blob/main/demo/flowcontrol/client.go",children:"client.go"}),", running it will call the SayHello API of layotto:"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-shell",children:" cd ${project_path}/demo/flowcontrol/\n go build -o client\n ./client\n"})}),"\n",(0,r.jsx)(t.p,{children:"Check the log of layotto, you will see the detailed tracking log printed out:"}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"img.png",src:n(574).A+"",width:"2481",height:"389"})}),"\n",(0,r.jsx)(t.h3,{id:"configuration-parameter-description",children:"Configuration parameter description"}),"\n",(0,r.jsx)(t.p,{children:"Trace configuration:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Field name"}),(0,r.jsx)(t.th,{children:"Field type"}),(0,r.jsx)(t.th,{children:"Description"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"enable"}),(0,r.jsx)(t.td,{children:"boolean"}),(0,r.jsx)(t.td,{children:"Global switch, whether to enable trace"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"driver"}),(0,r.jsx)(t.td,{children:"String"}),(0,r.jsx)(t.td,{children:"driver represents the type of trace, mosn has SOFATracer and skywalking, users can expand"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"config"}),(0,r.jsx)(t.td,{children:"Object"}),(0,r.jsx)(t.td,{children:"Trace expansion configuration"})]})]})]}),"\n",(0,r.jsx)(t.p,{children:"Trace expansion configuration:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Field name"}),(0,r.jsx)(t.th,{children:"Field type"}),(0,r.jsx)(t.th,{children:"Description"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"generator"}),(0,r.jsx)(t.td,{children:"String"}),(0,r.jsx)(t.td,{children:"SpanId, traceId and other resource generation methods, users can expand by themselves"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"exporter"}),(0,r.jsx)(t.td,{children:"Array"}),(0,r.jsx)(t.td,{children:"The way users need to report by trace can be implemented and expanded by themselves"})]})]})]}),"\n",(0,r.jsx)(t.h3,{id:"trace-mechanism",children:"Trace mechanism"}),"\n",(0,r.jsxs)(t.p,{children:["Tracing in Layotto is mainly to record grpc calls, which relies on two interceptors added in grpc\uff1a ",(0,r.jsx)(t.a,{href:"https://github.com/mosn/layotto/blob/main/diagnostics/grpc_tracing.go",children:"UnaryInterceptorFilter"})," \u3001 ",(0,r.jsx)(t.a,{href:"https://github.com/mosn/layotto/blob/main/diagnostics/grpc_tracing.go",children:"StreamInterceptorFilter"})]}),"\n",(0,r.jsx)(t.p,{children:"The interceptor will start tracing every time the grpc method is called, generate traceId spanId, a new context, record the method n
1ame, time, and pass the tracing information through the context, and finally export the span information when the method returns."}),"\n",(0,r.jsx)(t.h3,{id:"more-details-about-the-tracing-framework",children:"More details about the tracing framework"}),"\n",(0,r.jsx)(t.p,{children:"Overall diagram of the tracing framework:"}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"img.png",src:n(5186).A+"",width:"757",height:"314"})}),"\n",(0,r.jsx)(t.h4,{id:"span-structure",children:"Span structure:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-go",children:"type Span struct {\n StartTime time.Time //The time when the request was received\n EndTime time.Time //Returned time\n traceId string //traceId\n spanId string //spanId\n parentSpanId string // parent spanId\n tags [xprotocol.TRACE_END]string //Expand the field, the component can store its own information in this field\n operationName string\n}\n"})}),"\n",(0,r.jsx)(t.p,{children:"The Span structure defines the data structure passed between layotto and its component, as shown in the following figure, component can pass its own information to layotto through tags, and layotto does\nUnified trace report:"}),"\n",(0,r.jsx)(t.h4,{id:"generator-interface",children:"generator interface:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-go",children:"type Generator interface {\n GetTraceId(ctx context.Context) string\n GetSpanId(ctx context.Context) string\n GenerateNewContext(ctx context.Context, span api.Span) context.Context\n GetParentSpanId(ctx context.Context) string\n}\n"})}),"\n",(0,r.jsxs)(t.p,{children:["This interface corresponds to the generator configuration above. This interface is mainly used to generate traceId, spanId according to the received context, obtain the parent spanId and the function of the context passed to the component, the user\nYou can implement your own Generator, you can refer to the implementation of ",(0,r.jsx)(t.a,{href:"https://github.com/mosn/layotto/blob/main/diagnostics/genetator.go",children:"OpenGenerator"})," in the code."]}),"\n",(0,r.jsx)(t.h4,{id:"exporter-interface",children:"Exporter interface:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-go",children:"type Exporter interface {\n ExportSpan(s *Span)\n}\n"})}),"\n",(0,r.jsxs)(t.p,{children:["The exporter interface defines how to report Span information to the remote end, corresponding to the exporter field in the configuration, which is an array and can be reported to multiple servers. Can\nRefer to the implementation of ",(0,r.jsx)(t.a,{href:"https://github.com/mosn/layotto/blob/main/diagnostics/exporter_iml/stdout.go",children:"StdoutExporter"}),", which will print trace information to standard output."]}),"\n",(0,r.jsx)(t.h4,{id:"span-context-transfer",children:"Span context transfer:"}),"\n",(0,r.jsx)(t.h5,{id:"layotto-side",children:"Layotto side"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-go",children:"GenerateNewContext(ctx context.Context, span api.Span) context.Context\n"})}),"\n",(0,r.jsx)(t.p,{children:"GenerateNewContext is used to generate a new context, and Layotto use the variable ability of Mosn to realize the transfer of Span information between contexts:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-go",children:"_ = variable.Set(ctx, types.VariableTraceSpan, span)\n"})}),"\n",(0,r.jsxs)(t.p,{children:["You can refer to the implementation of ",(0,r.jsx)(t.a,{href:"https://github.com/mosn/layotto/blob/main/diagnostics/genetator.go",children:"OpenGenerator"})," in the code"]}),"\n",(0,r.jsx)(t.h5,{id:"component-side",children:"Component side"}),"\n",(0,r.jsxs)(t.p,{children:["On the Component side, you can insert component information through ",(0,r.jsx)(t.a,{href:"https://github.com/mosn/layotto/blob/main/components/trace/utils.go",children:"SetExtraComponentInfo"}),",\nFor example, the following operations are performed in the ",(0,r.jsx)(t.a,{href:"https://github.com/mosn/layotto/blob/main/components/configstores/etcdv3/etcdv3.go",children:"etcd configStore component"}),":"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-go",children:'trace.SetExtraComponentInfo(ctx, fmt.Sprintf("method: %+v, store: %+v", "Get", "etcd"))\n'})}),"\n",(0,r.jsx)(t.p,{children:"The results printed by trace are as follows:"}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"img.png",src:n(574).A+"",width:"2481",height:"389"})}),"\n",(0,r.jsx)(t.h2,{id:"2-metrics",children:"2. Metrics"}),"\n",(0,r.jsxs)(t.p,{children:["Layotto's metric reuses mosn's metric, and connects to prometheus. An example of metric configuration is provided in ",(0,r.jsx)(t.a,{href:"https://github.com/mosn/layotto/blob/main/configs/config_standalone.json",children:"config_standalone.json"}),", follow the above steps to start layotto After that, you can read the metric information through the following command:"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-shell",children:"curl --location --request GET 'http://127.0.0.1:34903/metrics'\n"})}),"\n",(0,r.jsx)(t.p,{children:"The result is shown below:"}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.img,{alt:"img.png",src:n(9145).A+"",width:"1412",height:"262"})}),"\n",(0,r.jsxs)(t.p,{children:["For the metric principle of mosn, please refer to ",(0,r.jsx)(t.a,{href:"https://mosn.io/blog/code/mosn-log/",children:"mosn official document"})]})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},9145:(e,t,n)=>{n.d(t,{A:()=>r});const r=n.p+"assets/images/metric-7fbf97bc1de45cd7194171fccecf8ccc.png"},5186:(e,t,n)=>{n.d(t,{A:()=>r});const r=n.p+"assets/images/structure-98be342f9c3b45d878a6ae91f34f83bc.png"}
1,574:(e,t,n)=>{n.d(t,{A:()=>r});const r=n.p+"assets/images/trace-fbcc4bcfecd0557f71a0a59d59aa600d.png"},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>s});var r=n(6540);const o={},a=r.createContext(o);function i(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function s(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:i(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.