diff --git a/docs/LICENSE_OF_DEPENDENCIES.md b/docs/LICENSE_OF_DEPENDENCIES.md index 2ed53c32c..fa829a426 100644 --- a/docs/LICENSE_OF_DEPENDENCIES.md +++ b/docs/LICENSE_OF_DEPENDENCIES.md @@ -190,6 +190,7 @@ following works: - github.com/grafana/regexp [BSD 3-Clause "New" or "Revised" License](https://github.com/grafana/regexp/blob/main/LICENSE) - github.com/grid-x/modbus [BSD 3-Clause "New" or "Revised" License](https://github.com/grid-x/modbus/blob/master/LICENSE) - github.com/grid-x/serial [MIT License](https://github.com/grid-x/serial/blob/master/LICENSE) +- github.com/grpc-ecosystem/grpc-gateway [BSD 3-Clause "New" or "Revised" License](https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE) - github.com/gsterjov/go-libsecret [MIT License](https://github.com/gsterjov/go-libsecret/blob/master/LICENSE) - github.com/gwos/tcg/sdk [MIT License](https://github.com/gwos/tcg/blob/master/LICENSE) - github.com/hailocab/go-hostpool [MIT License](https://github.com/hailocab/go-hostpool/blob/master/LICENSE) @@ -399,6 +400,7 @@ following works: - go.opentelemetry.io/otel [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE) - go.opentelemetry.io/otel/metric [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE) - go.opentelemetry.io/otel/trace [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-go/blob/main/LICENSE) +- go.opentelemetry.io/proto/otlp [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-proto-go/blob/main/LICENSE) - go.starlark.net [BSD 3-Clause "New" or "Revised" License](https://github.com/google/starlark-go/blob/master/LICENSE) - go.step.sm/crypto [Apache License 2.0](https://github.com/smallstep/crypto/blob/master/LICENSE) - go.uber.org/atomic [MIT License](https://pkg.go.dev/go.uber.org/atomic?tab=licenses) diff --git a/go.mod b/go.mod index a0dd6f94a..ac1a21ae7 100644 --- a/go.mod +++ b/go.mod @@ -205,9 +205,10 @@ require ( github.com/xdg/scram v1.0.5 github.com/yuin/goldmark v1.6.0 go.mongodb.org/mongo-driver v1.16.0 - go.opentelemetry.io/collector/pdata v1.8.0 + go.opentelemetry.io/collector/pdata v1.12.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 go.opentelemetry.io/otel/sdk/metric v1.27.0 + go.opentelemetry.io/proto/otlp v1.3.1 go.starlark.net v0.0.0-20240520160348-046347dcd104 go.step.sm/crypto v0.50.0 golang.org/x/crypto v0.25.0 @@ -492,7 +493,6 @@ require ( go.opentelemetry.io/otel/metric v1.27.0 // indirect go.opentelemetry.io/otel/sdk v1.27.0 // indirect go.opentelemetry.io/otel/trace v1.27.0 // indirect - go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect diff --git a/go.sum b/go.sum index e623ef196..a32e79694 100644 --- a/go.sum +++ b/go.sum @@ -2480,8 +2480,8 @@ go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/collector v0.81.0 h1:pF+sB8xNXlg/W0a0QTLz4mUWyool1a9toVj8LmLoFqg= go.opentelemetry.io/collector/consumer v0.101.0 h1:9tDxaeHe1+Uovf3fhdx7T4pV5mo/Dc0hniH7O5H3RBA= go.opentelemetry.io/collector/consumer v0.101.0/go.mod h1:ud5k64on9m7hHTrhjEeLhWbLkd8+Gp06rDt3p86TKNs= -go.opentelemetry.io/collector/pdata v1.8.0 h1:d/QQgZxB4Y+d3mqLVh2ozvzujUhloD3P/fk7X+In764= -go.opentelemetry.io/collector/pdata v1.8.0/go.mod h1:/W7clu0wFC4WSRp94Ucn6Vm36Wkrt+tmtlDb1aiNZCY= +go.opentelemetry.io/collector/pdata v1.12.0 h1:Xx5VK1p4VO0md8MWm2icwC1MnJ7f8EimKItMWw46BmA= +go.opentelemetry.io/collector/pdata v1.12.0/go.mod h1:MYeB0MmMAxeM0hstCFrCqWLzdyeYySim2dG6pDT6nYI= go.opentelemetry.io/collector/pdata/testdata v0.101.0 h1:JzeUtg5RN1iIFgY8DakGlqBkGxOTJlkaYlLausnEGKY= go.opentelemetry.io/collector/pdata/testdata v0.101.0/go.mod h1:ZGobfCus4fWo5RduZ7ENI0+HD9BewgKuO6qU2rBVnUg= go.opentelemetry.io/collector/semconv v0.101.0 h1:tOe9iTe9dDCnvz/bqgfNRr4w80kXG8505tQJ5h5v08Q= @@ -2509,8 +2509,8 @@ go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39S go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= -go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.starlark.net v0.0.0-20240520160348-046347dcd104 h1:3qhteRISupnJvaWshOmeqEUs2y9oc/+/ePPvDh3Eygg= go.starlark.net v0.0.0-20240520160348-046347dcd104/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8= go.step.sm/crypto v0.50.0 h1:BqI9sEgocoHDLLHiZnFqdqXl5FjdMvOWKMm/fKL/lrw= diff --git a/plugins/inputs/opentelemetry/README.md b/plugins/inputs/opentelemetry/README.md index f1517dab5..25cd26a06 100644 --- a/plugins/inputs/opentelemetry/README.md +++ b/plugins/inputs/opentelemetry/README.md @@ -42,10 +42,7 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details. ## These are always included as tags: ## - trace ID ## - span ID - ## The default values are strongly recommended for use with Jaeger: - ## - service.name - ## - span.name - ## Other common attributes can be found here: + ## Common attributes can be found here: ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv # span_dimensions = ["service.name", "span.name"] @@ -53,14 +50,25 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details. ## These are always included as tags, if available: ## - trace ID ## - span ID - ## The default values: - ## - service.name - ## Other common attributes can be found here: + ## Common attributes can be found here: ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv ## When using InfluxDB for both logs and traces, be certain that log_record_dimensions ## matches the span_dimensions value. # log_record_dimensions = ["service.name"] + ## Override the default profile attributes to be used as line protocol tags. + ## These are always included as tags, if available: + ## - profile_id + ## - address + ## - sample + ## - sample_name + ## - sample_unit + ## - sample_type + ## - sample_type_unit + ## Common attributes can be found here: + ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv + # profile_dimensions = [] + ## Override the default (prometheus-v1) metrics schema. ## Supports: "prometheus-v1", "prometheus-v2" ## For more information about the alternatives, read the Prometheus input @@ -148,3 +156,19 @@ logs fluent.tag="fluent.info",pid=18i,ppid=9i,worker=0i 1613769568895331700 logs fluent.tag="fluent.debug",instance=1720i,queue_size=0i,stage_size=0i 1613769568895697200 logs fluent.tag="fluent.info",worker=0i 1613769568896515100 ``` + +### Profiles + +```text +profiles,address=95210353,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=0,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="fab9b8c848218405738c11a7ec4982e9",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=18694144u,filename="chromium",frame_type="native",location="",memory_limit=250413056u,memory_start=18698240u,stack_trace_id="hYmAzQVF8vy8MWbzsKpQNw",start_time_unix_nano=1721306050081621681u,value=1i 1721306048731622020 +profiles,address=15945263,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="7dab4a2e0005d025e75cc72191f8d6bf",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename="dockerd",frame_type="native",location="",memory_limit=47255552u,memory_start=15638528u,stack_trace_id="4N3KEcGylb5Qoi2905c1ZA",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725 +profiles,address=15952400,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="7dab4a2e0005d025e75cc72191f8d6bf",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename="dockerd",frame_type="native",location="",memory_limit=47255552u,memory_start=15638528u,stack_trace_id="4N3KEcGylb5Qoi2905c1ZA",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725 +profiles,address=15953899,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="7dab4a2e0005d025e75cc72191f8d6bf",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename="dockerd",frame_type="native",location="",memory_limit=47255552u,memory_start=15638528u,stack_trace_id="4N3KEcGylb5Qoi2905c1ZA",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725 +profiles,address=16148175,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="7dab4a2e0005d025e75cc72191f8d6bf",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename="dockerd",frame_type="native",location="",memory_limit=47255552u,memory_start=15638528u,stack_trace_id="4N3KEcGylb5Qoi2905c1ZA",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725 +profiles,address=4770577,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="cfc3dc7d1638c1284a6b62d4b5c0d74e",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename="",frame_type="kernel",location="do_epoll_wait",memory_limit=0u,memory_start=0u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 +profiles,address=4773632,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="cfc3dc7d1638c1284a6b62d4b5c0d74e",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename="",frame_type="kernel",location="__x64_sys_epoll_wait",memory_limit=0u,memory_start=0u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 +profiles,address=14783666,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="cfc3dc7d1638c1284a6b62d4b5c0d74e",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename="",frame_type="kernel",location="do_syscall_64",memory_limit=0u,memory_start=0u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 +profiles,address=16777518,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="cfc3dc7d1638c1284a6b62d4b5c0d74e",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename="",frame_type="kernel",location="entry_SYSCALL_64_after_hwframe",memory_limit=0u,memory_start=0u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 +profiles,address=1139937,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="982ed6c7a77f99f0ae746be0187953bf",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=147456u,filename="libc.so.6",frame_type="native",location="",memory_limit=1638400u,memory_start=147456u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 +profiles,address=117834912,host.name=testbox,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="fab9b8c848218405738c11a7ec4982e9",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=18694144u,filename="chromium",frame_type="native",location="",memory_limit=250413056u,memory_start=18698240u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 +``` diff --git a/plugins/inputs/opentelemetry/grpc_service_profile.go b/plugins/inputs/opentelemetry/grpc_service_profile.go new file mode 100644 index 000000000..6638ee114 --- /dev/null +++ b/plugins/inputs/opentelemetry/grpc_service_profile.go @@ -0,0 +1,134 @@ +package opentelemetry + +import ( + "context" + "encoding/hex" + "fmt" + "strconv" + "strings" + "time" + + service "go.opentelemetry.io/proto/otlp/collector/profiles/v1experimental" + "google.golang.org/protobuf/encoding/protojson" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/filter" +) + +type profileService struct { + service.UnimplementedProfilesServiceServer + + acc telegraf.Accumulator + filter filter.Filter + logger telegraf.Logger +} + +func newProfileService(acc telegraf.Accumulator, logger telegraf.Logger, dimensions []string) (*profileService, error) { + // Check for duplicate dimensions + seen := make(map[string]bool, len(dimensions)) + duplicates := make([]string, 0) + dims := make([]string, 0, len(dimensions)) + for _, d := range dimensions { + if seen[d] { + duplicates = append(duplicates, d) + continue + } + dims = append(dims, d) + seen[d] = true + } + if len(duplicates) > 0 { + return nil, fmt.Errorf("duplicate profile dimension(s) configured: %s", strings.Join(duplicates, ",")) + } + f, err := filter.Compile(dims) + if err != nil { + return nil, fmt.Errorf("compiling dimensions filter failed: %w", err) + } + + return &profileService{ + acc: acc, + filter: f, + logger: logger, + }, nil +} + +func (s *profileService) Export(_ context.Context, req *service.ExportProfilesServiceRequest) (*service.ExportProfilesServiceResponse, error) { + // Output the received message for debugging + buf, err := protojson.Marshal(req) + if err != nil { + s.logger.Errorf("marshalling received profile failed: %v", err) + } else { + s.logger.Debugf("received profile: %s", string(buf)) + } + + for _, rp := range req.ResourceProfiles { + // Extract the requested attributes that should be added as tags + attrtags := make(map[string]string) + for _, attr := range rp.Resource.Attributes { + if s.filter.Match(attr.Key) { + attrtags[attr.Key] = attr.GetValue().GetStringValue() + } + } + + for _, sp := range rp.ScopeProfiles { + for _, p := range sp.Profiles { + for i, sample := range p.Profile.Sample { + for j := sample.LocationsStartIndex; j < sample.LocationsStartIndex+sample.LocationsLength; j++ { + for validx, value := range sample.Value { + loc := p.Profile.Location[j] + locations := make([]string, 0, len(loc.Line)) + for _, line := range loc.Line { + f := p.Profile.Function[line.FunctionIndex] + fileloc := p.Profile.StringTable[f.Filename] + if f.StartLine > 0 { + if fileloc != "" { + fileloc += " " + } + fileloc += "line " + strconv.FormatInt(f.StartLine, 10) + } + l := p.Profile.StringTable[f.Name] + if fileloc != "" { + l += "(" + fileloc + ")" + } + locations = append(locations, l) + } + mapping := p.Profile.Mapping[loc.MappingIndex] + tags := map[string]string{ + "profile_id": hex.EncodeToString(p.ProfileId), + "sample": strconv.Itoa(i), + "sample_name": p.Profile.StringTable[p.Profile.PeriodType.Type], + "sample_unit": p.Profile.StringTable[p.Profile.PeriodType.Unit], + "sample_type": p.Profile.StringTable[p.Profile.SampleType[validx].Type], + "sample_type_unit": p.Profile.StringTable[p.Profile.SampleType[validx].Unit], + "address": "0x" + strconv.FormatUint(loc.Address, 16), + } + for k, v := range attrtags { + tags[k] = v + } + fields := map[string]interface{}{ + "start_time_unix_nano": p.StartTimeUnixNano, + "end_time_unix_nano": p.EndTimeUnixNano, + "location": strings.Join(locations, ","), + "frame_type": p.Profile.StringTable[loc.TypeIndex], + "stack_trace_id": p.Profile.StringTable[sample.StacktraceIdIndex], + "memory_start": mapping.MemoryStart, + "memory_limit": mapping.MemoryLimit, + "filename": p.Profile.StringTable[mapping.Filename], + "file_offset": mapping.FileOffset, + "build_id": p.Profile.StringTable[mapping.BuildId], + "build_id_type": mapping.BuildIdKind.String(), + "value": value, + } + for _, idx := range sample.Attributes { + attr := p.Profile.AttributeTable[idx] + fields[attr.Key] = attr.GetValue().Value + } + ts := sample.TimestampsUnixNano[validx] + s.acc.AddFields("profiles", fields, tags, time.Unix(0, int64(ts))) + } + } + } + } + } + } + return &service.ExportProfilesServiceResponse{}, nil +} diff --git a/plugins/inputs/opentelemetry/opentelemetry.go b/plugins/inputs/opentelemetry/opentelemetry.go index 4bb299c29..6b6bd5a69 100644 --- a/plugins/inputs/opentelemetry/opentelemetry.go +++ b/plugins/inputs/opentelemetry/opentelemetry.go @@ -8,13 +8,14 @@ import ( "sync" "time" - "github.com/influxdata/influxdb-observability/otel2influx" "go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" + pprofileotlp "go.opentelemetry.io/proto/otlp/collector/profiles/v1experimental" "google.golang.org/grpc" "google.golang.org/grpc/credentials" + "github.com/influxdata/influxdb-observability/otel2influx" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/config" "github.com/influxdata/telegraf/plugins/common/tls" @@ -28,11 +29,11 @@ type OpenTelemetry struct { ServiceAddress string `toml:"service_address"` SpanDimensions []string `toml:"span_dimensions"` LogRecordDimensions []string `toml:"log_record_dimensions"` + ProfileDimensions []string `toml:"profile_dimensions"` MetricsSchema string `toml:"metrics_schema"` MaxMsgSize config.Size `toml:"max_msg_size"` Timeout config.Duration `toml:"timeout"` Log telegraf.Logger `toml:"-"` - tls.ServerConfig listener net.Listener // overridden in tests @@ -45,11 +46,26 @@ func (*OpenTelemetry) SampleConfig() string { return sampleConfig } -func (o *OpenTelemetry) Gather(_ telegraf.Accumulator) error { +func (*OpenTelemetry) Gather(telegraf.Accumulator) error { return nil } -func (o *OpenTelemetry) Start(accumulator telegraf.Accumulator) error { +func (o *OpenTelemetry) Init() error { + if o.ServiceAddress == "" { + o.ServiceAddress = "0.0.0.0:4317" + } + switch o.MetricsSchema { + case "": // Set default + o.MetricsSchema = "prometheus-v1" + case "prometheus-v1", "prometheus-v2": // Valid values + default: + return fmt.Errorf("invalid metric schema %q", o.MetricsSchema) + } + + return nil +} + +func (o *OpenTelemetry) Start(acc telegraf.Accumulator) error { var grpcOptions []grpc.ServerOption if tlsConfig, err := o.ServerConfig.TLSConfig(); err != nil { return err @@ -64,7 +80,7 @@ func (o *OpenTelemetry) Start(accumulator telegraf.Accumulator) error { } logger := &otelLogger{o.Log} - influxWriter := &writeToAccumulator{accumulator} + influxWriter := &writeToAccumulator{acc} o.grpcServer = grpc.NewServer(grpcOptions...) traceSvc, err := newTraceService(logger, influxWriter, o.SpanDimensions) @@ -72,30 +88,36 @@ func (o *OpenTelemetry) Start(accumulator telegraf.Accumulator) error { return err } ptraceotlp.RegisterGRPCServer(o.grpcServer, traceSvc) + metricsSvc, err := newMetricsService(logger, influxWriter, o.MetricsSchema) if err != nil { return err } pmetricotlp.RegisterGRPCServer(o.grpcServer, metricsSvc) + logsSvc, err := newLogsService(logger, influxWriter, o.LogRecordDimensions) if err != nil { return err } plogotlp.RegisterGRPCServer(o.grpcServer, logsSvc) - if o.listener == nil { - o.listener, err = net.Listen("tcp", o.ServiceAddress) - if err != nil { - return err - } + profileSvc, err := newProfileService(acc, o.Log, o.ProfileDimensions) + if err != nil { + return err + } + pprofileotlp.RegisterProfilesServiceServer(o.grpcServer, profileSvc) + + o.listener, err = net.Listen("tcp", o.ServiceAddress) + if err != nil { + return err } o.wg.Add(1) go func() { + defer o.wg.Done() if err := o.grpcServer.Serve(o.listener); err != nil { - accumulator.AddError(fmt.Errorf("failed to stop OpenTelemetry gRPC service: %w", err)) + acc.AddError(fmt.Errorf("failed to stop OpenTelemetry gRPC service: %w", err)) } - o.wg.Done() }() return nil @@ -105,6 +127,7 @@ func (o *OpenTelemetry) Stop() { if o.grpcServer != nil { o.grpcServer.Stop() } + o.listener = nil o.wg.Wait() } @@ -112,10 +135,8 @@ func (o *OpenTelemetry) Stop() { func init() { inputs.Add("opentelemetry", func() telegraf.Input { return &OpenTelemetry{ - ServiceAddress: "0.0.0.0:4317", SpanDimensions: otel2influx.DefaultOtelTracesToLineProtocolConfig().SpanDimensions, LogRecordDimensions: otel2influx.DefaultOtelLogsToLineProtocolConfig().LogRecordDimensions, - MetricsSchema: "prometheus-v1", Timeout: config.Duration(5 * time.Second), } }) diff --git a/plugins/inputs/opentelemetry/opentelemetry_test.go b/plugins/inputs/opentelemetry/opentelemetry_test.go index 70888fccb..f4492e941 100644 --- a/plugins/inputs/opentelemetry/opentelemetry_test.go +++ b/plugins/inputs/opentelemetry/opentelemetry_test.go @@ -3,78 +3,250 @@ package opentelemetry import ( "context" "net" + "os" + "path/filepath" + "runtime" + "sort" + "strings" "testing" "time" - "go.opentelemetry.io/otel/sdk/metric/metricdata" - + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + otlplogs "go.opentelemetry.io/proto/otlp/collector/logs/v1" + otlpmetrics "go.opentelemetry.io/proto/otlp/collector/metrics/v1" + otlpprofiles "go.opentelemetry.io/proto/otlp/collector/profiles/v1experimental" + otlptrace "go.opentelemetry.io/proto/otlp/collector/trace/v1" "google.golang.org/grpc" - "google.golang.org/grpc/test/bufconn" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/encoding/protojson" + "github.com/influxdata/influxdb-observability/otel2influx" "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" + tmetric "github.com/influxdata/telegraf/metric" "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/parsers/influx" "github.com/influxdata/telegraf/testutil" ) func TestOpenTelemetry(t *testing.T) { - // create mock OpenTelemetry client + // Setup and start the plugin + plugin := &OpenTelemetry{ + MetricsSchema: "prometheus-v1", + } + require.NoError(t, plugin.Init()) - mockListener := bufconn.Listen(1024 * 1024) - t.Cleanup(func() { _ = mockListener.Close() }) - plugin := inputs.Inputs["opentelemetry"]().(*OpenTelemetry) - plugin.listener = mockListener - accumulator := new(testutil.Accumulator) - - require.NoError(t, plugin.Start(accumulator)) - t.Cleanup(plugin.Stop) + var acc testutil.Accumulator + require.NoError(t, plugin.Start(&acc)) + defer plugin.Stop() + // Setup the OpenTelemetry exporter ctx, cancel := context.WithTimeout(context.Background(), time.Second) - t.Cleanup(cancel) + defer cancel() - metricExporter, err := otlpmetricgrpc.New(ctx, + exporter, err := otlpmetricgrpc.New(ctx, otlpmetricgrpc.WithInsecure(), otlpmetricgrpc.WithDialOption( - grpc.WithBlock(), //nolint:staticcheck // grpc.WithBlock is deprecated, but no alternative is provided - grpc.WithContextDialer(func(ctx context.Context, _ string) (net.Conn, error) { - return mockListener.DialContext(ctx) + grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { + return net.Dial("tcp", plugin.listener.Addr().String()) })), ) require.NoError(t, err) - //nolint:errcheck // test cleanup - t.Cleanup(func() { metricExporter.Shutdown(ctx) }) + defer exporter.Shutdown(ctx) //nolint:errcheck // We cannot do anything if the shutdown fails + // Setup the metric to send reader := metric.NewManualReader() - mp := metric.NewMeterProvider(metric.WithReader(reader)) + defer reader.Shutdown(ctx) //nolint:errcheck // We cannot do anything if the shutdown fails - // set a metric value - - meter := mp.Meter("library-name") + provider := metric.NewMeterProvider(metric.WithReader(reader)) + meter := provider.Meter("library-name") counter, err := meter.Int64Counter("measurement-counter") require.NoError(t, err) counter.Add(ctx, 7) - // write metrics through the telegraf OpenTelemetry input plugin - + // Write the OpenTelemetry metrics var rm metricdata.ResourceMetrics - err = reader.Collect(ctx, &rm) - require.NoError(t, err) - require.NoError(t, metricExporter.Export(ctx, &rm)) + require.NoError(t, reader.Collect(ctx, &rm)) + require.NoError(t, exporter.Export(ctx, &rm)) // Shutdown - require.NoError(t, reader.Shutdown(ctx)) - require.NoError(t, metricExporter.Shutdown(ctx)) + require.NoError(t, exporter.Shutdown(ctx)) plugin.Stop() // Check + require.Empty(t, acc.Errors) - require.Empty(t, accumulator.Errors) - require.Len(t, accumulator.Metrics, 1) - got := accumulator.Metrics[0] - require.Equal(t, "measurement-counter", got.Measurement) - require.Equal(t, telegraf.Counter, got.Type) - require.Equal(t, "library-name", got.Tags["otel.library.name"]) + var exesuffix string + if runtime.GOOS == "windows" { + exesuffix = ".exe" + } + expected := []telegraf.Metric{ + tmetric.New( + "measurement-counter", + map[string]string{ + "otel.library.name": "library-name", + "service.name": "unknown_service:opentelemetry.test" + exesuffix, + "telemetry.sdk.language": "go", + "telemetry.sdk.name": "opentelemetry", + "telemetry.sdk.version": "1.27.0", + }, + map[string]interface{}{ + "counter": 7, + }, + time.Unix(0, 0), + telegraf.Counter, + ), + } + actual := acc.GetTelegrafMetrics() + testutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.IgnoreFields("start_time_unix_nano")) +} + +func TestCases(t *testing.T) { + // Get all directories in testdata + folders, err := os.ReadDir("testcases") + require.NoError(t, err) + + // Register the plugin + inputs.Add("opentelemetry", func() telegraf.Input { + return &OpenTelemetry{ + ServiceAddress: "127.0.0.1:0", + SpanDimensions: otel2influx.DefaultOtelTracesToLineProtocolConfig().SpanDimensions, + LogRecordDimensions: otel2influx.DefaultOtelLogsToLineProtocolConfig().LogRecordDimensions, + ProfileDimensions: []string{"host.name"}, + Timeout: config.Duration(5 * time.Second), + } + }) + + // Prepare the influx parser for expectations + parser := &influx.Parser{} + require.NoError(t, parser.Init()) + + for _, f := range folders { + // Only handle folders + if !f.IsDir() { + continue + } + testcasePath := filepath.Join("testcases", f.Name()) + configFilename := filepath.Join(testcasePath, "telegraf.conf") + inputFiles := filepath.Join(testcasePath, "*.json") + expectedFilename := filepath.Join(testcasePath, "expected.out") + expectedErrorFilename := filepath.Join(testcasePath, "expected.err") + + // Compare options + options := []cmp.Option{ + testutil.IgnoreTime(), + testutil.SortMetrics(), + testutil.IgnoreFields("start_time_unix_nano"), + } + + t.Run(f.Name(), func(t *testing.T) { + // Read the input data + inputs := make(map[string][][]byte) + matches, err := filepath.Glob(inputFiles) + require.NoError(t, err) + require.NotEmpty(t, matches) + sort.Strings(matches) + for _, fn := range matches { + buf, err := os.ReadFile(fn) + require.NoError(t, err) + + key := strings.TrimSuffix(filepath.Base(fn), ".json") + key, _, _ = strings.Cut(key, "_") + inputs[key] = append(inputs[key], buf) + } + + // Read the expected output if any + var expected []telegraf.Metric + if _, err := os.Stat(expectedFilename); err == nil { + var err error + expected, err = testutil.ParseMetricsFromFile(expectedFilename, parser) + require.NoError(t, err) + } + + // Read the expected output if any + var expectedErrors []string + if _, err := os.Stat(expectedErrorFilename); err == nil { + var err error + expectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFilename) + require.NoError(t, err) + require.NotEmpty(t, expectedErrors) + } + + // Configure the plugin + cfg := config.NewConfig() + require.NoError(t, cfg.LoadConfig(configFilename)) + require.Len(t, cfg.Inputs, 1) + + // Setup and start the plugin + plugin := cfg.Inputs[0].Input.(*OpenTelemetry) + require.NoError(t, plugin.Init()) + + var acc testutil.Accumulator + require.NoError(t, plugin.Start(&acc)) + defer plugin.Stop() + + // Send all data to the plugin + addr := plugin.listener.Addr().String() + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + grpcClient, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + require.NoError(t, err) + defer grpcClient.Close() + for msgtype, messages := range inputs { + switch msgtype { + case "logs": + client := otlplogs.NewLogsServiceClient(grpcClient) + for _, buf := range messages { + var msg otlplogs.ExportLogsServiceRequest + require.NoError(t, protojson.Unmarshal(buf, &msg)) + _, err := client.Export(ctx, &msg) + require.NoError(t, err) + } + case "metrics": + client := otlpmetrics.NewMetricsServiceClient(grpcClient) + for _, buf := range messages { + var msg otlpmetrics.ExportMetricsServiceRequest + require.NoError(t, protojson.Unmarshal(buf, &msg)) + _, err := client.Export(ctx, &msg) + require.NoError(t, err) + } + case "profiles": + client := otlpprofiles.NewProfilesServiceClient(grpcClient) + for _, buf := range messages { + var msg otlpprofiles.ExportProfilesServiceRequest + require.NoError(t, protojson.Unmarshal(buf, &msg)) + _, err := client.Export(ctx, &msg) + require.NoError(t, err) + } + case "traces": + client := otlptrace.NewTraceServiceClient(grpcClient) + for _, buf := range messages { + var msg otlptrace.ExportTraceServiceRequest + require.NoError(t, protojson.Unmarshal(buf, &msg)) + _, err := client.Export(ctx, &msg) + require.NoError(t, err) + } + } + } + + // Close the plugin to make sure all data is flushed + require.NoError(t, grpcClient.Close()) + plugin.Stop() + + // Check the metrics + require.Eventually(t, func() bool { + return acc.NMetrics() >= uint64(len(expected)) + }, 3*time.Second, 100*time.Millisecond) + require.Empty(t, acc.Errors) + + actual := acc.GetTelegrafMetrics() + testutil.RequireMetricsEqual(t, expected, actual, options...) + }) + } } diff --git a/plugins/inputs/opentelemetry/sample.conf b/plugins/inputs/opentelemetry/sample.conf index 0c7cf7852..95ff435df 100644 --- a/plugins/inputs/opentelemetry/sample.conf +++ b/plugins/inputs/opentelemetry/sample.conf @@ -14,10 +14,7 @@ ## These are always included as tags: ## - trace ID ## - span ID - ## The default values are strongly recommended for use with Jaeger: - ## - service.name - ## - span.name - ## Other common attributes can be found here: + ## Common attributes can be found here: ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv # span_dimensions = ["service.name", "span.name"] @@ -25,14 +22,25 @@ ## These are always included as tags, if available: ## - trace ID ## - span ID - ## The default values: - ## - service.name - ## Other common attributes can be found here: + ## Common attributes can be found here: ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv ## When using InfluxDB for both logs and traces, be certain that log_record_dimensions ## matches the span_dimensions value. # log_record_dimensions = ["service.name"] + ## Override the default profile attributes to be used as line protocol tags. + ## These are always included as tags, if available: + ## - profile_id + ## - address + ## - sample + ## - sample_name + ## - sample_unit + ## - sample_type + ## - sample_type_unit + ## Common attributes can be found here: + ## - https://github.com/open-telemetry/opentelemetry-collector/tree/main/semconv + # profile_dimensions = [] + ## Override the default (prometheus-v1) metrics schema. ## Supports: "prometheus-v1", "prometheus-v2" ## For more information about the alternatives, read the Prometheus input diff --git a/plugins/inputs/opentelemetry/testcases/profiles/expected.out b/plugins/inputs/opentelemetry/testcases/profiles/expected.out new file mode 100644 index 000000000..6207f0be2 --- /dev/null +++ b/plugins/inputs/opentelemetry/testcases/profiles/expected.out @@ -0,0 +1,11 @@ +profiles,address=0x5accb71,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=0,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="fab9b8c848218405738c11a7ec4982e9",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=18694144u,filename="chromium",frame_type="native",location="",memory_limit=250413056u,memory_start=18698240u,stack_trace_id="hYmAzQVF8vy8MWbzsKpQNw",start_time_unix_nano=1721306050081621681u,value=1i 1721306048731622020 +profiles,address=0xf34e2f,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="7dab4a2e0005d025e75cc72191f8d6bf",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename="dockerd",frame_type="native",location="",memory_limit=47255552u,memory_start=15638528u,stack_trace_id="4N3KEcGylb5Qoi2905c1ZA",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725 +profiles,address=0xf36a10,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="7dab4a2e0005d025e75cc72191f8d6bf",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename="dockerd",frame_type="native",location="",memory_limit=47255552u,memory_start=15638528u,stack_trace_id="4N3KEcGylb5Qoi2905c1ZA",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725 +profiles,address=0xf36feb,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="7dab4a2e0005d025e75cc72191f8d6bf",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename="dockerd",frame_type="native",location="",memory_limit=47255552u,memory_start=15638528u,stack_trace_id="4N3KEcGylb5Qoi2905c1ZA",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725 +profiles,address=0xf666cf,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=1,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="7dab4a2e0005d025e75cc72191f8d6bf",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=15638528u,filename="dockerd",frame_type="native",location="",memory_limit=47255552u,memory_start=15638528u,stack_trace_id="4N3KEcGylb5Qoi2905c1ZA",start_time_unix_nano=1721306050081621681u,value=1i 1721306049831718725 +profiles,address=0x48cb11,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="cfc3dc7d1638c1284a6b62d4b5c0d74e",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename="",frame_type="kernel",location="do_epoll_wait",memory_limit=0u,memory_start=0u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 +profiles,address=0x48d700,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="cfc3dc7d1638c1284a6b62d4b5c0d74e",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename="",frame_type="kernel",location="__x64_sys_epoll_wait",memory_limit=0u,memory_start=0u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 +profiles,address=0xe194b2,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="cfc3dc7d1638c1284a6b62d4b5c0d74e",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename="",frame_type="kernel",location="do_syscall_64",memory_limit=0u,memory_start=0u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 +profiles,address=0x100012e,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="cfc3dc7d1638c1284a6b62d4b5c0d74e",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=0u,filename="",frame_type="kernel",location="entry_SYSCALL_64_after_hwframe",memory_limit=0u,memory_start=0u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 +profiles,address=0x1164e1,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="982ed6c7a77f99f0ae746be0187953bf",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=147456u,filename="libc.so.6",frame_type="native",location="",memory_limit=1638400u,memory_start=147456u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 +profiles,address=0x70604a0,host.name=Hugin,profile_id=618098d29a6cefd6a4c0ea806880c2a8,sample=2,sample_name=cpu,sample_type=samples,sample_type_unit=count,sample_unit=nanoseconds build_id="fab9b8c848218405738c11a7ec4982e9",build_id_type="BUILD_ID_BINARY_HASH",end_time_unix_nano=1721306050081621681u,file_offset=18694144u,filename="chromium",frame_type="native",location="",memory_limit=250413056u,memory_start=18698240u,stack_trace_id="UaO9bysJnAYXFYobSdHXqg",start_time_unix_nano=1721306050081621681u,value=1i 1721306050081621681 diff --git a/plugins/inputs/opentelemetry/testcases/profiles/profiles.json b/plugins/inputs/opentelemetry/testcases/profiles/profiles.json new file mode 100644 index 000000000..b839ff6a1 --- /dev/null +++ b/plugins/inputs/opentelemetry/testcases/profiles/profiles.json @@ -0,0 +1,699 @@ +{ + "resourceProfiles": [ + { + "resource": { + "attributes": [ + { + "key": "profiling.agent.start_time", + "value": { + "stringValue": "1721306026320" + } + }, + { + "key": "profiling.agent.env_https_proxy", + "value": { + "stringValue": "" + } + }, + { + "key": "profiling.agent.config.tracers", + "value": { + "stringValue": "all" + } + }, + { + "key": "profiling.agent.config.ca_address", + "value": { + "stringValue": "127.0.0.1:11000" + } + }, + { + "key": "host:cpu/cache/L2-kbytes", + "value": { + "stringValue": "512" + } + }, + { + "key": "profiling.host.kernel_version", + "value": { + "stringValue": "6.9.9-arch1-1" + } + }, + { + "key": "profiling.agent.config.verbose", + "value": { + "stringValue": "false" + } + }, + { + "key": "host:cpu/vendor/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/cores-per-socket", + "value": { + "stringValue": "8" + } + }, + { + "key": "profiling.host.sysctl.kernel.unprivileged_bpf_disabled", + "value": { + "stringValue": "2" + } + }, + { + "key": "profiling.agent.revision", + "value": { + "stringValue": "main-172652de" + } + }, + { + "key": "host:cpu/clock/scaling-governor", + "value": { + "stringValue": "schedutil" + } + }, + { + "key": "host:cpu/cache/L3-kbytes", + "value": { + "stringValue": "16384" + } + }, + { + "key": "host:cpu/clock/min-mhz", + "value": { + "stringValue": "2200" + } + }, + { + "key": "host:cpu/clock/scaling-cur-freq-mhz", + "value": { + "stringValue": "2226" + } + }, + { + "key": "host:cpu/cpus", + "value": { + "stringValue": "16" + } + }, + { + "key": "host:cpu/clock/min-mhz/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/cache/L2-kbytes/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "profiling.host.machine", + "value": { + "stringValue": "x86_64" + } + }, + { + "key": "profiling.agent.version", + "value": { + "stringValue": "v0.0.0" + } + }, + { + "key": "host:cpu/clock/max-mhz/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/flags", + "value": { + "stringValue": "3dnowprefetch,abm,adx,aes,aperfmperf,apic,arat,avic,avx,avx2,bmi1,bmi2,bpext,cat_l3,cdp_l3,clflush,clflushopt,clwb,clzero,cmov,cmp_legacy,constant_tsc,cpb,cpuid,cqm,cqm_llc,cqm_mbm_local,cqm_mbm_total,cqm_occup_llc,cr8_legacy,cx16,cx8,de,decodeassists,extapic,extd_apicid,f16c,flushbyasid,fma,fpu,fsgsbase,fxsr,fxsr_opt,ht,hw_pstate,ibpb,ibs,irperf,lahf_lm,lbrv,lm,mba,mca,mce,misalignsse,mmx,mmxext,monitor,movbe,msr,mtrr,mwaitx,nonstop_tsc,nopl,npt,nrip_save,nx,osvw,overflow_recov,pae,pat,pausefilter,pclmulqdq,pdpe1gb,perfctr_core,perfctr_llc,perfctr_nb,pfthreshold,pge,pni,popcnt,pse,pse36,rapl,rdpid,rdpru,rdrand,rdseed,rdt_a,rdtscp,rep_good,sep,sev,sev_es,sha_ni,skinit,smap,smca,smep,ssbd,sse,sse2,sse4_1,sse4_2,sse4a,ssse3,stibp,succor,svm,svm_lock,syscall,tce,topoext,tsc,tsc_scale,umip,v_spec_ctrl,v_vmsave_vmload,vgif,vmcb_clean,vme,vmmcall,wbnoinvd,wdt,x2apic,xgetbv1,xsave,xsavec,xsaveerptr,xsaveopt,xtopology" + } + }, + { + "key": "profiling.agent.config.max_elements_per_interval", + "value": { + "stringValue": "1600" + } + }, + { + "key": "host:cpu/model/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/clock/scaling-governor/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "profiling.agent.config.known_traces_entries", + "value": { + "stringValue": "65536" + } + }, + { + "key": "profiling.agent.config.probabilistic_threshold", + "value": { + "stringValue": "100" + } + }, + { + "key": "host:cpu/cache/L1i-kbytes/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/stepping", + "value": { + "stringValue": "0" + } + }, + { + "key": "profiling.agent.config.probabilistic_interval", + "value": { + "stringValue": "1m0s" + } + }, + { + "key": "profiling.agent.config.map_scale_factor", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/cpus/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/bugs/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/clock/scaling-driver/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/cache/L3-kbytes/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/cores-per-socket/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/clock/scaling-cur-freq-mhz/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "profiling.host.name", + "value": { + "stringValue": "Hugin" + } + }, + { + "key": "host:cpu/clock/max-mhz", + "value": { + "stringValue": "4426" + } + }, + { + "key": "profiling.host.sysctl.net.core.bpf_jit_enable", + "value": { + "stringValue": "1" + } + }, + { + "key": "profiling.agent.config.bpf_log_size", + "value": { + "stringValue": "65536" + } + }, + { + "key": "profiling.agent.config.present_cpu_cores", + "value": { + "stringValue": "16" + } + }, + { + "key": "profiling.agent.build_timestamp", + "value": { + "stringValue": "1721228980" + } + }, + { + "key": "profiling.host.kernel_proc_version", + "value": { + "stringValue": "Linux version 6.9.9-arch1-1 (linux@archlinux) (gcc (GCC) 14.1.1 20240522, GNU ld (GNU Binutils) 2.42.0) #1 SMP PREEMPT_DYNAMIC Fri, 12 Jul 2024 00:06:53 +0000\n" + } + }, + { + "key": "host:cpu/threads-per-core/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/cache/L1d-kbytes/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "profiling.agent.config.file", + "value": { + "stringValue": "/etc/otel/profiling-agent/agent.conf" + } + }, + { + "key": "profiling.agent.config.disable_tls", + "value": { + "stringValue": "true" + } + }, + { + "key": "profiling.host.sysctl.kernel.bpf_stats_enabled", + "value": { + "stringValue": "0" + } + }, + { + "key": "profiling.agent.config.tags", + "value": { + "stringValue": "" + } + }, + { + "key": "host:cpu/clock/scaling-driver", + "value": { + "stringValue": "acpi-cpufreq" + } + }, + { + "key": "host:cpu/online/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/cache/L1d-kbytes", + "value": { + "stringValue": "32" + } + }, + { + "key": "profiling.agent.config.bpf_log_level", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/model-name/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host.arch", + "value": { + "stringValue": "amd64" + } + }, + { + "key": "host:cpu/bugs", + "value": { + "stringValue": "retbleed,smt_rsb,spec_store_bypass,spectre_v1,spectre_v2,srso,sysret_ss_attrs" + } + }, + { + "key": "host:cpu/threads-per-core", + "value": { + "stringValue": "2" + } + }, + { + "key": "host:cpu/online", + "value": { + "stringValue": "0-15" + } + }, + { + "key": "host:cpu/stepping/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/model-name", + "value": { + "stringValue": "AMD Ryzen 7 3700X 8-Core Processor" + } + }, + { + "key": "profiling.host.ip", + "value": { + "stringValue": "127.0.0.1" + } + }, + { + "key": "profiling.agent.config.cache_directory", + "value": { + "stringValue": "/var/cache/otel/profiling-agent" + } + }, + { + "key": "profiling.agent.config.no_kernel_version_check", + "value": { + "stringValue": "false" + } + }, + { + "key": "host:cpu/model", + "value": { + "stringValue": "113" + } + }, + { + "key": "host:cpu/vendor", + "value": { + "stringValue": "AuthenticAMD" + } + }, + { + "key": "host:cpu/flags/socketIDs", + "value": { + "stringValue": "0" + } + }, + { + "key": "host:cpu/cache/L1i-kbytes", + "value": { + "stringValue": "32" + } + }, + { + "key": "profiling.project.id", + "value": { + "stringValue": "1" + } + }, + { + "key": "host.id", + "value": { + "stringValue": "1693958027216639598" + } + }, + { + "key": "host.ip", + "value": { + "stringValue": "127.0.0.1" + } + }, + { + "key": "host.name", + "value": { + "stringValue": "Hugin" + } + }, + { + "key": "service.version", + "value": { + "stringValue": "" + } + }, + { + "key": "os.kernel", + "value": { + "stringValue": "6.9.9-arch1-1" + } + } + ] + }, + "scopeProfiles": [ + { + "scope": {}, + "profiles": [ + { + "profileId": "YYCY0pps79akwOqAaIDCqA==", + "startTimeUnixNano": "1721306050081621681", + "endTimeUnixNano": "1721306050081621681", + "profile": { + "sampleType": [ + { + "type": "1", + "unit": "2" + } + ], + "sample": [ + { + "locationsLength": "1", + "stacktraceIdIndex": 5, + "value": [ + "1" + ], + "attributes": [ + "0" + ], + "timestampsUnixNano": [ + "1721306048731622020" + ] + }, + { + "locationsStartIndex": "1", + "locationsLength": "4", + "stacktraceIdIndex": 9, + "value": [ + "1" + ], + "attributes": [ + "1" + ], + "timestampsUnixNano": [ + "1721306049831718725" + ] + }, + { + "locationsStartIndex": "5", + "locationsLength": "6", + "stacktraceIdIndex": 12, + "value": [ + "1" + ], + "attributes": [ + "2" + ], + "timestampsUnixNano": [ + "1721306050081621681" + ] + } + ], + "mapping": [ + { + "memoryStart": "18698240", + "memoryLimit": "250413056", + "fileOffset": "18694144", + "filename": "7", + "buildId": "8", + "buildIdKind": "BUILD_ID_BINARY_HASH" + }, + { + "memoryStart": "15638528", + "memoryLimit": "47255552", + "fileOffset": "15638528", + "filename": "10", + "buildId": "11", + "buildIdKind": "BUILD_ID_BINARY_HASH" + }, + { + "buildId": "14", + "buildIdKind": "BUILD_ID_BINARY_HASH" + }, + { + "memoryStart": "147456", + "memoryLimit": "1638400", + "fileOffset": "147456", + "filename": "15", + "buildId": "16", + "buildIdKind": "BUILD_ID_BINARY_HASH" + } + ], + "location": [ + { + "address": "95210353", + "typeIndex": 6 + }, + { + "mappingIndex": "1", + "address": "15945263", + "typeIndex": 6 + }, + { + "mappingIndex": "1", + "address": "15952400", + "typeIndex": 6 + }, + { + "mappingIndex": "1", + "address": "15953899", + "typeIndex": 6 + }, + { + "mappingIndex": "1", + "address": "16148175", + "typeIndex": 6 + }, + { + "mappingIndex": "2", + "address": "4770577", + "line": [ + { + "functionIndex": "1" + } + ], + "typeIndex": 13 + }, + { + "mappingIndex": "2", + "address": "4773632", + "line": [ + { + "functionIndex": "2" + } + ], + "typeIndex": 13 + }, + { + "mappingIndex": "2", + "address": "14783666", + "line": [ + { + "functionIndex": "3" + } + ], + "typeIndex": 13 + }, + { + "mappingIndex": "2", + "address": "16777518", + "line": [ + { + "functionIndex": "4" + } + ], + "typeIndex": 13 + }, + { + "mappingIndex": "3", + "address": "1139937", + "typeIndex": 6 + }, + { + "address": "117834912", + "typeIndex": 6 + } + ], + "locationIndices": [ + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10" + ], + "function": [ + {}, + { + "name": "20" + }, + { + "name": "17" + }, + { + "name": "18" + }, + { + "name": "19" + } + ], + "attributeTable": [ + { + "key": "thread.name", + "value": { + "stringValue": "chromium" + } + }, + { + "key": "thread.name", + "value": { + "stringValue": "dockerd" + } + }, + { + "key": "thread.name", + "value": { + "stringValue": "ThreadPoolServi" + } + } + ], + "stringTable": [ + "", + "samples", + "count", + "cpu", + "nanoseconds", + "hYmAzQVF8vy8MWbzsKpQNw", + "native", + "chromium", + "fab9b8c848218405738c11a7ec4982e9", + "4N3KEcGylb5Qoi2905c1ZA", + "dockerd", + "7dab4a2e0005d025e75cc72191f8d6bf", + "UaO9bysJnAYXFYobSdHXqg", + "kernel", + "cfc3dc7d1638c1284a6b62d4b5c0d74e", + "libc.so.6", + "982ed6c7a77f99f0ae746be0187953bf", + "__x64_sys_epoll_wait", + "do_syscall_64", + "entry_SYSCALL_64_after_hwframe", + "do_epoll_wait" + ], + "timeNanos": "1721306050081621681", + "periodType": { + "type": "3", + "unit": "4" + }, + "period": "50000000" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/plugins/inputs/opentelemetry/testcases/profiles/telegraf.conf b/plugins/inputs/opentelemetry/testcases/profiles/telegraf.conf new file mode 100644 index 000000000..390e1cf0e --- /dev/null +++ b/plugins/inputs/opentelemetry/testcases/profiles/telegraf.conf @@ -0,0 +1 @@ +[[inputs.opentelemetry]]