ããã«ã¡ã¯ã»ããã°ãã¯ã»ãã¯ãããããã¾ããã¨ã³ã¸ãã¢ã®
id:aerealã§ãã
ãã®è¨äºã§ã¯çè ãéçºã«åå ãã¦ãããµã¼ãã¹ã®ç£è¦ãã¬ã¼ã ã¯ã¼ã¯ãOpenTelemetryã¸ç§»è¡ããéã®ä½é¨ãç´¹ä»ãã¾ãã
OpenTelemetryã¨ã¯
OpenTelemetry is an Observability framework and toolkit designed to create and manage telemetry data such as traces, metrics, and logs.
What is OpenTelemetry?
ãµã¤ãã®èª¬æã«ããéã忣ãã¬ã¼ã¹ãã¡ããªã¯ã¹ããã°ãªã©ã®ææ¨ãæ±ãç£è¦ãã¬ã¼ã ã¯ã¼ã¯ã§ãã
OpenTracingãOpenCensusãªã©ãç¶æ¿ã»çµ±åããããã¸ã§ã¯ãã¨è¨ãã¨åç¹ãããæ¹ãå¤ãã®ã§ã¯ãªãã§ããããã
OpenTelemetryã¯ãææ¨ã屿§ãªã©ã®æå³è«ããããã³ã«ãå®ãã仿§ãããã仿§ãå®ç¾ããåè¨èªã®å®è£ ãããã¦ãããã³ã«ã«å¾ããã¼ã¿ãå¦çã»éåä¿¡ããCollectorã®è¨3ã¤ããããã¾ãã«æãç«ã£ã¦ãã¾ãã
ã¢ããªã±ã¼ã·ã§ã³ã«SDKãçµã¿è¾¼ã¿ããµã¤ãã«ã¼ãããã¯ã²ã¼ãã¦ã§ã¤ã¨ãã¦é ç½®ããCollectorã«å¯¾ãåææ¨ãéããCollectorã¯è¨å®ã§è¨è¿°ãããéãã«ææ¨ãå å·¥ãå¤é¨ãµã¼ãã¹ã¸éä¿¡ããã¨ããæµãã«ãªã£ã¦ãã¾ãã
ã¢ããªã±ã¼ã·ã§ã³ã¯SDKãä»ãã¦OpenTelemetryãããã³ã«ã§Collectorã«éä¿¡ãããã¨ã ãã«é¢å¿ãæã¦ã°ããããã®ææ¨ãã©ã®ããã«å¤é¨ãµã¼ãã¹ã¸éä¿¡ããããã¯Collectorã¸ä»»ããããã¨ããç¹ãåãã³ãã®SDKãããããå©ç¨ããå ´åã«å¯¾ããå©ç¹ã§ãã
ã¾ãCollectorã¯ãããã¡ãªã³ã°ã ãã§ã¯ãªãã屿§ (attributes) ã¨å¼ã°ããææ¨ã®ã¡ã¿ãã¼ã¿ã追å ã»å å·¥ã»åé¤ããä»çµã¿ãã屿§ããã¨ã«éä¿¡å ãå¤ããããéä¿¡ãããææ¨ãéç©ãã¦ã«ã¦ã³ã¿å¤ãçæããã¨ãã£ãé«åº¦ãªä»çµã¿ãåãã¦ãã¾ãã
Collectorã¯å ¬å¼ã«æä¾ããããªãªã¼ã¹ãã«ãã®ã»ããçµã¿è¾¼ãã³ã³ãã¼ãã³ããã«ã¹ã¿ãã¤ãºãã¦ãã«ãããæ¹æ³ãæä¾ããã¦ãããçµç¹å é¨ã§å ±éãã¦å©ç¨ãããã³ã³ãã¼ãã³ãã®çµã¿è¾¼ã¿ãæ¯è¼çç°¡åã«ãªã£ã¦ãã¾ãã ãã®ç¹ã«é¢ãã¦ãã¾ãæ©ä¼ãæ¹ãã¦ç´¹ä»ãããã¨æãã¾ãã
Classiã§æ¡ç¨ããçç±
å½ç¤¾ã§æ°è¦éçºãããµã¼ãã¹ã¯AWSã®ããã¼ã¸ããµã¼ãã¹ãç©æ¥µçã«åãå ¥ãã¦ãããã³ã¼ããæ¸ãã¦æ§ç¯ããã¢ããªã±ã¼ã·ã§ã³ã¨ããã¼ã¸ããµã¼ãã¹ã®å¢çã¯ææ§ã«ãªã£ã¦ãã¦ããããã対çãªåå¨ã«ãªã£ã¦ãã¾ãã
refs. dron: ã¯ã©ã¦ããã¤ãã£ããªcron代æ¿ã®ç´¹ä» - Classiéçºè ããã°
ãããªè¤æ°ã®ã³ã³ãã¼ãã³ããããªãã¢ããªã±ã¼ã·ã§ã³ãç£è¦ããä¸ã§åæ£ãã¬ã¼ã·ã³ã°ã¯æ¬ ããã¾ããã
Classiã§ã¯ç£è¦ã½ãªã¥ã¼ã·ã§ã³ã¨ãã¦Datadogãå°å ¥ã»æ´»ç¨ãã¦ãã¾ã:
- Datadogã§ECS Fargate Taskã®CPUå©ç¨çã100%ãè¶ ãã¦è¡¨ç¤ºããã¦ããã®ã§èª¿ã¹ã¦ã¿ã - Classiéçºè ããã°
- Datadogã§æ·±å¤ãããã®å¤±æã¢ã©ã¼ããå¶æ¥æéã«åãåãæ¹æ³ - Classiéçºè ããã°
- å°å ¥äºä¾ï¼Classiæ ªå¼ä¼ç¤¾ | Datadog
忣ãã¬ã¼ã·ã³ã°ãDatadog APMãæ´»ç¨ãã¦ãã¾ããå®éãå ã®è¨äºã§ç´¹ä»ããdronãã¯ããã¨ãããã¹ã¦ã®Classiã®ãµã¼ãã¹ã§ã¯Datadogã®SDKãç¨ãã¦APMã¸ãã¬ã¼ã¹ãéã£ã¦ãã¾ããã
䏿¹ãStep Functionsãªã©ã®AWSã®ããã¼ã¸ããµã¼ãã¹ã¯åæ£ãã¬ã¼ã·ã³ã°ã«å¯¾å¿ãã¦ãã¾ããããã¬ã¼ã¹ã®åéå ã¯AWS X-Rayã®ã¿ã§ãã ãã¬ã¼ã¹ãDatadog APMã®ã¿ã«éã£ã¦ããã¨X-Rayã®ã¿ã«åå¨ããããã¼ã¸ããµã¼ãã¹ã®ãã¬ã¼ã¹ã¨æçµ¶ãã¦ãã¾ãã¾ãã
仿¹ããªãã¢ããªã±ã¼ã·ã§ã³ã¯AWS X-Ray SDKã¨Datadog APM SDKã® ä¸¡æ¹ ãå°å ¥ããX-Rayã¨Datadog APMã®ä¸¡æ¹ã¸ãã¬ã¼ã¹ãéããã¨ã«ãã¦ãã¾ããã ãããããã¬ã¼ã¹ã®ã¡ã¿ãã¼ã¿è¿½å ãªã©ããããå®è£ ãäºåº¦æéã«ãªããå®è£ ã®æãæ¼ããèµ·ãããããªãã¾ãã
å®éãã¢ããªã±ã¼ã·ã§ã³ã®ä¸èª¿ã調ã¹ãããã«APMãè¦ããDatadog APMã«ã¯ã»ããã¡ã¿ãã¼ã¿ãéã£ã¦ããªãã£ãã¨ãããã¨ãèµ·ããã»ã¨ã»ã¨å«æ°ãå·®ããã®ã§äºéã®è¨è£ ããããã¹ã調æ»ãã¯ãããOpenTelemetryã«è¡ãçãã¾ããã
ãªãX-Rayã¸çµ±ä¸ããã¨ãã鏿è¢ã¯ãã¢ã©ã¼ãã®è¨å®ãªã©ç£è¦å ¨è¬ãDatadogã«å¯ããæ¹éã§ãã£ããã¨ã»ãããå·®ãå¼ãã¦ãDatadogã®ã»ãã使ãåæãè¯ãã£ããã¨ãããæ¤è¨ãã¦ãã¾ããã
ã¢ããªã±ã¼ã·ã§ã³ã¸ã®å°å ¥
ç£è¦SDKã¨ãã¦OpenTelemetryã¸ç§»è¡ãããã¨ã«æ±ºãããã¨ã«ãããã¨ã¯è³ã£ã¦åç´ã§ãããã¥ã¡ã³ãã«å¾ãã©ã¤ãã©ãªãå°å ¥ããOpenTelemetry Collectorããµã¤ãã«ã¼ã«è¿½å ããåä½ç¢ºèªããã¾ãã
ç§»è¡ä¸ã®åºæ¬çãªåä½ç¢ºèªããéã¯ãå®éã«X-RayãDatadogã«éãããããã¼ã«ã«ã§èµ·åããZipkinãéä¿¡å ã«è¨å®ããCollectorãåããã¨ç´ æ©ããã©ã¤ã¢ã³ãã¨ã©ã¼ãç¹°ãè¿ãããã«ãªãã¨ã¦ãéå®ãã¾ããã
ãã¡ããåexporterã®å¤æå¦çãæã¾ããã¨ã»ããã夿ãè¨å®ã«ãã£ã¦ç°ãªããã¨ãããæçµçã«ã¯å®éã«X-RayãDatadogã«éã£ãä¸ã§ç¢ºèªãã¹ãã§ããããã¨ãã°ããããåéãããã¹ãã³ãéããã¦ãããã¨ãããã¡ãã¨å±æ§ã追å ã§ãã¦ãããã¨ãããããã£ãåºæ¬çãªç¢ºèªã¯Zipkinã§ãååã§ãã
屿§ã®ç®¡ç
OpenTelemetryã¯å±æ§ (attributes) ã¨å¼ã°ããã¡ã¿ãã¼ã¿ããã¬ã¼ã¹ãã¡ããªã¯ã¹ãªã©ã®åææ¨ã«ç´ä»ãããã¾ãã
ãããã¯X-Rayã§ã¯ã¢ããã¼ã·ã§ã³ã»Datadogã§ã¯ã¿ã°ã«ãããã夿ããã¾ãã
屿§ã¯ææ¨ã®æ å ±éãå¢ããç£è¦ã大ãã«å©ãã¦ããã¾ãããã¢ããªã±ã¼ã·ã§ã³å ¨ä½ã§çµ±ä¸ãã¦ãããªãã¨ããã¨ããæã«ä½¿ãã¾ããã
ããã§å±æ§ãè¨å®ãã¡ã¤ã«ã§ç®¡çãã屿§ãæ³¨å ¥ããå®è£ ã¯è¨å®ãã¡ã¤ã«ããçæãã颿°ã ããè¡ããããã«ãããã¨ã§ãã¢ããªã±ã¼ã·ã§ã³å ¨ä½ã§ä½¿ããã¦ãã屿§ãçµ±ä¸ãããã¨ã«ãã¾ããã
以ä¸ã«å®éã®è¨å®ãã¡ã¤ã«ã®ä¾ãç´¹ä»ãã¾ã:
--- # yaml-language-server: $schema=./telemetry.schema.json attributes: db_migration.is_dirty: { type: bool } db_migration.step: { type: int } git.commit.sha: type: string description: | ç¾å¨åãã¦ããã³ãããããã·ã¥ã表ã屿§åã Datadogã®active commit linkingã«ä½¿ãã refs. https://docs.datadoghq.com/integrations/guide/source-code-integration/?tab=dockerruntime#tag-your-telemetry git.repository_url: type: string description: | ãµã¼ãã¹ã®ã½ã¼ã¹ã³ã¼ãããã¹ãããã¦ãããªãã¸ããªãæã屿§å¤ã Datadogã®active commit linkingã«ä½¿ãã refs. https://docs.datadoghq.com/integrations/guide/source-code-integration/?tab=dockerruntime#tag-your-telemetry measurements: test_import_count: { type: Int64Gauge }
ã¾ãã¹ãã¼ãã¯ä»¥ä¸ã®éãã§ã:
{ "type": "object", "properties": { "attributes": { "$ref": "#/definitions/attributes" }, "measurements": { "$ref": "#/definitions/measurements" } }, "definitions": { "deprecationDescription": { "type": "object", "properties": { "reason": { "type": "string" } }, "required": [ "reason" ] }, "attributeValueType": { "enum": [ "string", "bool", "int", "int64" ] }, "attributeDefinition": { "type": "object", "properties": { "type": { "$ref": "#/definitions/attributeValueType" }, "deprecated": { "$ref": "#/definitions/deprecationDescription" }, "description": { "type": "string" } }, "required": [ "type" ] }, "attributes": { "type": "object", "patternProperties": { ".+": { "$ref": "#/definitions/attributeDefinition" } } }, "measurementType": { "enum": [ "Float64Counter", "Float64Gauge", "Float64Histogram", "Float64UpDownCounter", "Int64Counter", "Int64Gauge", "Int64Histogram", "Int64UpDownCounter" ] }, "measurementDefinition": { "type": "object", "properties": { "type": { "$ref": "#/definitions/measurementType" } } }, "measurements": { "type": "object", "patternProperties": { ".+": { "$ref": "#/definitions/measurementDefinition" } } } } }
attributes.$name.type: 屿§ã®åãstringãintãªã©OpenTelemetryã®ä»æ§ã«å¾ãattributes.$name.description: 屿§ã®èª¬æãçç¥å¯è½ã§ãçæãããã³ã¼ãã®ããã¥ã¡ã³ãã«ãå«ã¾ãã
VS Codeã«redhat.vscode-yamlãå ¥ãã¦ããã¨ããã¼ã«ã«ã«é ç½®ããJSON Schemaãèªã¿è¾¼ãã§ãã£ã¼ã«ãã®è£å®ãè¡ã£ã¦ããã¾ãã
以ä¸ã«ä¸è¨ãã¡ã¤ã«ããçæãããGoã®ã³ã¼ããè¼ãã¾ã:
// KeyDbMigrationIsDirty is an attribute key that means "db_migration.is_dirty". var KeyDbMigrationIsDirty = attribute.Key("db_migration.is_dirty") // AttrDbMigrationIsDirty returns a new attribute that named "db_migration.is_dirty". func AttrDbMigrationIsDirty(v ...bool) attribute.KeyValue { switch { case len(v) == 0: return emptyKeyValue case len(v) == 1: return KeyDbMigrationIsDirty.Bool(v[0]) default: return KeyDbMigrationIsDirty.BoolSlice(v) } } // KeyDbMigrationStep is an attribute key that means "db_migration.step". var KeyDbMigrationStep = attribute.Key("db_migration.step") // AttrDbMigrationStep returns a new attribute that named "db_migration.step". func AttrDbMigrationStep(v ...int) attribute.KeyValue { switch { case len(v) == 0: return emptyKeyValue case len(v) == 1: return KeyDbMigrationStep.Int(v[0]) default: return KeyDbMigrationStep.IntSlice(v) } } // KeyGitCommitSha is an attribute key that means "git.commit.sha". // // ç¾å¨åãã¦ããã³ãããããã·ã¥ã表ã屿§åã // Datadogã®active commit linkingã«ä½¿ãã // // refs. https://docs.datadoghq.com/integrations/guide/source-code-integration/?tab=dockerruntime#tag-your-telemetry var KeyGitCommitSha = attribute.Key("git.commit.sha") // AttrGitCommitSha returns a new attribute that named "git.commit.sha". // // ç¾å¨åãã¦ããã³ãããããã·ã¥ã表ã屿§åã // Datadogã®active commit linkingã«ä½¿ãã // // refs. https://docs.datadoghq.com/integrations/guide/source-code-integration/?tab=dockerruntime#tag-your-telemetry func AttrGitCommitSha(v ...string) attribute.KeyValue { switch { case len(v) == 0: return emptyKeyValue case len(v) == 1: return KeyGitCommitSha.String(v[0]) default: return KeyGitCommitSha.StringSlice(v) } } // KeyGitRepositoryUrl is an attribute key that means "git.repository_url". // // ãµã¼ãã¹ã®ã½ã¼ã¹ã³ã¼ãããã¹ãããã¦ãããªãã¸ããªãæã屿§å¤ã // Datadogã®active commit linkingã«ä½¿ãã // // refs. https://docs.datadoghq.com/integrations/guide/source-code-integration/?tab=dockerruntime#tag-your-telemetry var KeyGitRepositoryUrl = attribute.Key("git.repository_url") // AttrGitRepositoryUrl returns a new attribute that named "git.repository_url". // // ãµã¼ãã¹ã®ã½ã¼ã¹ã³ã¼ãããã¹ãããã¦ãããªãã¸ããªãæã屿§å¤ã // Datadogã®active commit linkingã«ä½¿ãã // // refs. https://docs.datadoghq.com/integrations/guide/source-code-integration/?tab=dockerruntime#tag-your-telemetry func AttrGitRepositoryUrl(v ...string) attribute.KeyValue { switch { case len(v) == 0: return emptyKeyValue case len(v) == 1: return KeyGitRepositoryUrl.String(v[0]) default: return KeyGitRepositoryUrl.StringSlice(v) } }
ã覧ã®éãè¨å®ãã¡ã¤ã«ã«è¨è¿°ãã description ã颿°ã®ã³ã¡ã³ãã«å«ã¾ãã¦ãã¾ãã
æå¾ã«ä»¥ä¸ã®ããã«ã¢ããªã±ã¼ã·ã§ã³å
ã®ä»»æã®ãã¡ã¤ã«ãã go.opentelemetry.io/otel/attribute ãç¨ãã¦è¨å®ãã¡ã¤ã«ã§ç®¡çããã¦ããªã屿§ã®è¿½å ãã§ããªãããgolangci-lintãè¨å®ãã¾ã:
linters:
disable-all: true
enable:
- forbidigo
linters-settings:
forbidigo:
forbid:
- "^attribute[.]"
å³å¯ã«ã¯ attribute. ã§å§ã¾ãå¼ãéåã¨ãªããã®ã§æ³å®ãããã¡ã¸ã¼ã§ããå®ç¨ä¸å°ã£ã¦ããªãã®ã§ãã®ã¾ã¾ã¨ãã¾ãã
æå¾ã«ã³ã¼ãçæã«ä½¿ã£ãã¹ã¯ãªããã以ä¸ã«ç¤ºãã¾ã:
generate-signals/main.go
package main import ( "bytes" _ "embed" "errors" "flag" "fmt" "go/format" "os" "path/filepath" "sort" "strconv" "strings" "text/template" "unicode" "gopkg.in/yaml.v3" ) var ( //go:embed src.gotpl tmplBody string pkg string typeName string doFormat bool configPath string outPath string errPkgRequired = errors.New("-pkg is required") errOutRequired = errors.New("-out is required") ) func main() { if err := run(); err != nil { fmt.Fprintf(os.Stderr, "%+v\n", err) os.Exit(1) } } func run() error { flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", filepath.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if pkg == "" { return errPkgRequired } if outPath == "" { return errOutRequired } parsed, err := template.New("src.gotpl"). Funcs(template.FuncMap{"quote": strconv.Quote, "prefixLines": prefixLines}). Parse(tmplBody) if err != nil { return fmt.Errorf("template.Parse: %w", err) } cfg, err := readConfig(configPath) if err != nil { return fmt.Errorf("readConfig: %w", err) } attrs := make([]*attribute, 0, len(cfg.Attributes)) for name, def := range cfg.Attributes { def := def a := &attribute{Name: name, Type: def.Type, Description: def.Description} if def.Deprecation != nil { a.DeprecationReason = def.Deprecation.Reason } attrs = append(attrs, a) } measurements := make([]*measurement, 0, len(cfg.Measurements)) for name, def := range cfg.Measurements { def := def measurements = append(measurements, &measurement{Name: name, DataType: def.DataType}) } sort.Slice(attrs, func(i, j int) bool { return attrs[i].Name < attrs[j].Name }) sort.Slice(measurements, func(i, j int) bool { return measurements[i].Name < measurements[j].Name }) out := new(bytes.Buffer) data := struct { Package string Attributes []*attribute Measurements []*measurement TypeName string SingletonName string }{ Package: pkg, Attributes: attrs, Measurements: measurements, TypeName: typeName, SingletonName: "Measurements", } if err := parsed.Execute(out, data); err != nil { return fmt.Errorf("template.Execute: %w", err) } body := out.Bytes() if doFormat { var err error body, err = format.Source(body) if err != nil { return fmt.Errorf("format.Source: %w", err) } } if err := os.WriteFile(outPath, body, 0600); err != nil { return fmt.Errorf("os.WriteFile(%s): %w", outPath, err) } return nil } type attribute struct { Name string Type string DeprecationReason string Description string } func (a *attribute) inputType() (elmType string, isSlice bool) { t, ok := strings.CutPrefix(a.Type, "[]") return t, ok } func (a *attribute) ElemType() string { et, _ := a.inputType() return et } func (a *attribute) AttributeConstructor() string { cn, _ := a.inputType() return strings.ToUpper(string(cn[0])) + cn[1:] } func (a *attribute) AttributeSliceConstructor() string { return a.AttributeConstructor() + "Slice" } func (a *attribute) GoType() string { return a.Type } func (a *attribute) Identifier() string { b := new(strings.Builder) shouldUpNextRune := true for _, r := range a.Name { switch { case shouldUpNextRune: b.WriteRune(unicode.ToUpper(r)) shouldUpNextRune = false case r == '_' || r == '.': shouldUpNextRune = true default: b.WriteRune(r) } } return b.String() } type measurement struct { Name string DataType string } func (m *measurement) QualifiedName() string { return "app." + m.Name } func (m *measurement) FieldName() string { b := new(strings.Builder) shouldUpNextRune := true for _, r := range m.Name { switch { case shouldUpNextRune: b.WriteRune(unicode.ToUpper(r)) shouldUpNextRune = false case r == '_': shouldUpNextRune = true default: b.WriteRune(r) } } return b.String() } func (m *measurement) SDKReturnType() string { switch m.DataType { case "Int64Gauge": return "Int64ObservableGauge" case "Float64Gauge": return "Float64ObservableGauge" default: return m.DataType } } type deprecationDescription struct { Reason string `yaml:"reason"` } type attributeDefinition struct { Type string `yaml:"type"` Deprecation *deprecationDescription `yaml:"deprecated"` Description string `yaml:"description"` } type measurementDefinition struct { DataType string `yaml:"type"` } type telemetryConfig struct { Attributes map[string]*attributeDefinition `yaml:"attributes"` Measurements map[string]*measurementDefinition `yaml:"measurements"` } func readConfig(cfgPath string) (*telemetryConfig, error) { f, err := os.Open(cfgPath) if err != nil { return nil, err } defer f.Close() cfg := new(telemetryConfig) if err := yaml.NewDecoder(f).Decode(cfg); err != nil { return nil, err } return cfg, nil } func prefixLines(prefix, s string) string { return prefix + strings.ReplaceAll(s, "\n", "\n"+prefix) } func init() { flag.StringVar(&pkg, "package", "observability", "package name") flag.StringVar(&typeName, "type", "MeasurementDefinition", "type name") flag.StringVar(&configPath, "config", "etc/telemetry.yml", "config file path") flag.BoolVar(&doFormat, "format", true, "whether do format") flag.StringVar(&outPath, "out", "", "output file path") }
package {{ .Package }}
// Code generated by tools/gen-telemetry-signal/main.go; DO NOT EDIT.
import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
)
var emptyKeyValue attribute.KeyValue
{{ range $attr := .Attributes }}
// Key{{ $attr.Identifier }} is an attribute key that means {{ $attr.Name | quote }}.
{{- with $attr.Description }}
//
{{ . | prefixLines "// " }}{{ end }}
{{- with $attr.DeprecationReason }}
//
{{ (. | printf "Deprecated: %s") | prefixLines "// " }}{{ end }}
var Key{{ $attr.Identifier }} = attribute.Key({{ $attr.Name | quote }})
// Attr{{ $attr.Identifier }} returns a new attribute that named {{ $attr.Name | quote }}.
{{- with $attr.Description }}
//
{{ . | prefixLines "// " }}{{ end }}
{{- with $attr.DeprecationReason }}
//
{{ (. | printf "Deprecated: %s") | prefixLines "// " }}{{ end }}
func Attr{{ $attr.Identifier }}(v ...{{ $attr.ElemType }}) attribute.KeyValue {
switch {
case len(v) == 0:
return emptyKeyValue
case len(v) == 1:
return Key{{ $attr.Identifier }}.{{ $attr.AttributeConstructor }}(v[0])
default:
return Key{{ $attr.Identifier }}.{{ $attr.AttributeSliceConstructor }}(v)
}
}
{{ end -}}
// measurements
func {{ .SingletonName }}() {{ .TypeName }} {
return __singleton_{{ .SingletonName }}
}
var __singleton_{{ .SingletonName }} = {{ .TypeName }}{
{{- range $measurement := .Measurements -}}
{{ $measurement.FieldName }}: {{ $measurement.QualifiedName | quote }},
{{- end -}}
}
type {{ .TypeName }} struct {
{{ range $measurement := .Measurements }}
{{ $measurement.FieldName }} string
{{- end -}}
}
{{ range $measurement := .Measurements }}
func Measure{{ $measurement.FieldName }}(meter metric.Meter) (metric.{{ $measurement.SDKReturnType }}, error) {
return meter.{{ $measurement.SDKReturnType }}({{ $measurement.QualifiedName | quote }})
}
{{ end -}}
ããã³
AWS X-Rayããã³Datadog APMã¸ãã¬ã¼ã¹ãéãä»çµã¿ã¨ãã¦OpenTelemetryãæ¡ç¨ã»ç§»è¡ããçµç·¯ã¨å ·ä½çãªã¨ãã½ã¼ããç´¹ä»ãã¾ããã
ä»ã«ãOpenTelemetryãæ´»ç¨ããä¸ã§æ§ã ãªåãçµã¿ããã¦ããã®ã§ä»å¾ãç´¹ä»ãããã¨æãã¾ãã