diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b7566977..ab210ebbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ OpenTelemetry Go Automatic Instrumentation adheres to [Semantic Versioning](http - Support `google.golang.org/grpc` `1.63.3`. ([#916](https://github.com/open-telemetry/opentelemetry-go-instrumentation/pull/916)) - Support `google.golang.org/grpc` `1.64.1`. ([#916](https://github.com/open-telemetry/opentelemetry-go-instrumentation/pull/916)) - Support `golang.org/x/net` `v0.27.0`. ([#917](https://github.com/open-telemetry/opentelemetry-go-instrumentation/pull/917)) +- The `otelglobal` probe now collects the user provided tracer name, version and schemaURL. ([#844](https://github.com/open-telemetry/opentelemetry-go-instrumentation/pull/844)) ### Changed diff --git a/examples/kafka-go/consumer/go.mod b/examples/kafka-go/consumer/go.mod index 923e551a1..2ccfa7feb 100644 --- a/examples/kafka-go/consumer/go.mod +++ b/examples/kafka-go/consumer/go.mod @@ -5,6 +5,7 @@ go 1.22.0 require ( github.com/segmentio/kafka-go v0.4.47 go.opentelemetry.io/otel v1.28.0 + go.opentelemetry.io/otel/trace v1.28.0 ) require ( @@ -13,5 +14,4 @@ require ( github.com/klauspost/compress v1.15.9 // indirect github.com/pierrec/lz4/v4 v4.1.15 // indirect go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect ) diff --git a/examples/kafka-go/consumer/main.go b/examples/kafka-go/consumer/main.go index b67996b1a..cacab5eb9 100644 --- a/examples/kafka-go/consumer/main.go +++ b/examples/kafka-go/consumer/main.go @@ -25,9 +25,10 @@ import ( kafka "github.com/segmentio/kafka-go" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) -var tracer = otel.Tracer("trace-example") +var tracer = otel.Tracer("trace-example-kafka-go", trace.WithInstrumentationVersion("v1.0.0-test")) func getKafkaReader() *kafka.Reader { return kafka.NewReader(kafka.ReaderConfig{ diff --git a/examples/kafka-go/producer/go.mod b/examples/kafka-go/producer/go.mod index 1c8c46503..e65a5ddad 100644 --- a/examples/kafka-go/producer/go.mod +++ b/examples/kafka-go/producer/go.mod @@ -4,8 +4,9 @@ go 1.22.0 require github.com/segmentio/kafka-go v0.4.47 +require github.com/stretchr/testify v1.9.0 // indirect + require ( github.com/klauspost/compress v1.15.9 // indirect github.com/pierrec/lz4/v4 v4.1.15 // indirect - github.com/stretchr/testify v1.9.0 // indirect ) diff --git a/internal/include/go_types.h b/internal/include/go_types.h index 45861a245..364e19131 100644 --- a/internal/include/go_types.h +++ b/internal/include/go_types.h @@ -23,30 +23,36 @@ Keep a power of 2 to help with masks */ #define MAX_SLICE_ARRAY_SIZE 1024 -struct go_string +typedef struct go_string { char *str; s64 len; -}; +} go_string_t; -struct go_slice +typedef struct go_slice { void *array; s64 len; s64 cap; -}; +} go_slice_t; -struct go_iface +typedef struct go_iface { void *tab; void *data; -}; - -struct map_bucket { - char tophash[8]; - struct go_string keys[8]; - struct go_slice values[8]; - void *overflow; +} go_iface_t; + +// a map bucket type with the given key and value types +#define MAP_BUCKET_TYPE(key_type, value_type) struct map_bucket_##key_type##_##value_type##_t +// a map bucket struct definition with the given key and value types +// for more details about the structure of a map bucket see: +// https://github.com/golang/go/blob/639cc0dcc0948dd02c9d5fc12fbed730a21ebebc/src/runtime/map.go#L143 +#define MAP_BUCKET_DEFINITION(key_type, value_type) \ +MAP_BUCKET_TYPE(key_type, value_type) { \ + char tophash[8]; \ + key_type keys[8]; \ + value_type values[8]; \ + void *overflow; \ }; struct slice_array_buff diff --git a/internal/pkg/inject/offset_results.json b/internal/pkg/inject/offset_results.json index e66a8d736..1d86c6dfd 100644 --- a/internal/pkg/inject/offset_results.json +++ b/internal/pkg/inject/offset_results.json @@ -941,6 +941,293 @@ ] } ] + }, + { + "field": "name", + "offsets": [ + { + "offset": null, + "versions": [ + "0.1.0", + "0.1.1", + "0.1.2", + "0.2.0", + "0.2.1", + "0.2.2", + "0.2.3", + "0.3.0", + "0.4.0", + "0.4.1", + "0.4.2", + "0.4.3", + "0.5.0", + "0.6.0", + "0.7.0", + "0.8.0", + "0.9.0", + "0.10.0", + "0.11.0", + "0.12.0", + "0.13.0" + ] + }, + { + "offset": 0, + "versions": [ + "0.19.0", + "0.20.0", + "1.0.0-RC1", + "1.0.0-RC2", + "1.0.0-RC3", + "1.0.0", + "1.0.1", + "1.1.0", + "1.2.0", + "1.3.0", + "1.4.0", + "1.4.1", + "1.5.0", + "1.6.0", + "1.6.1", + "1.6.2", + "1.6.3", + "1.7.0", + "1.8.0", + "1.9.0", + "1.10.0", + "1.11.0", + "1.11.1", + "1.11.2", + "1.12.0", + "1.13.0", + "1.14.0", + "1.15.0-rc.1", + "1.15.0-rc.2", + "1.15.0", + "1.15.1", + "1.16.0-rc.1", + "1.16.0", + "1.17.0", + "1.18.0", + "1.19.0-rc.1", + "1.19.0" + ] + }, + { + "offset": 16, + "versions": [ + "0.14.0", + "0.15.0", + "0.16.0", + "0.17.0", + "0.18.0", + "1.20.0", + "1.21.0", + "1.22.0", + "1.23.0-rc.1", + "1.23.0", + "1.23.1", + "1.24.0", + "1.25.0", + "1.26.0", + "1.27.0", + "1.28.0" + ] + } + ] + }, + { + "field": "provider", + "offsets": [ + { + "offset": null, + "versions": [ + "0.1.0", + "0.1.1", + "0.1.2", + "0.2.0", + "0.2.1", + "0.2.2", + "0.2.3", + "0.3.0", + "0.4.0", + "0.4.1", + "0.4.2", + "0.4.3", + "0.5.0", + "0.6.0", + "0.7.0", + "0.8.0", + "0.9.0", + "0.10.0", + "0.11.0", + "0.12.0", + "0.13.0", + "0.14.0", + "0.15.0", + "0.16.0", + "0.17.0", + "0.18.0", + "0.19.0", + "0.20.0" + ] + }, + { + "offset": 40, + "versions": [ + "1.0.0-RC1", + "1.0.0-RC2", + "1.0.0-RC3", + "1.0.0", + "1.0.1", + "1.1.0", + "1.2.0", + "1.3.0", + "1.4.0", + "1.4.1", + "1.5.0", + "1.6.0", + "1.6.1", + "1.6.2", + "1.6.3", + "1.7.0", + "1.8.0", + "1.9.0", + "1.10.0", + "1.11.0", + "1.11.1", + "1.11.2", + "1.12.0", + "1.13.0", + "1.14.0", + "1.15.0-rc.1", + "1.15.0-rc.2", + "1.15.0", + "1.15.1", + "1.16.0-rc.1", + "1.16.0", + "1.17.0", + "1.18.0", + "1.19.0-rc.1", + "1.19.0" + ] + }, + { + "offset": 56, + "versions": [ + "1.20.0", + "1.21.0", + "1.22.0", + "1.23.0-rc.1", + "1.23.0", + "1.23.1", + "1.24.0", + "1.25.0", + "1.26.0", + "1.27.0", + "1.28.0" + ] + } + ] + } + ] + }, + { + "struct": "tracerProvider", + "fields": [ + { + "field": "tracers", + "offsets": [ + { + "offset": null, + "versions": [ + "0.1.0", + "0.1.1", + "0.1.2", + "0.2.0", + "0.2.1", + "0.2.2", + "0.2.3", + "0.3.0", + "0.4.0", + "0.4.1", + "0.4.2", + "0.4.3", + "0.5.0", + "0.6.0", + "0.7.0", + "0.8.0", + "0.9.0", + "0.10.0", + "0.11.0", + "0.12.0", + "0.13.0" + ] + }, + { + "offset": 8, + "versions": [ + "0.14.0", + "0.15.0", + "0.16.0", + "0.17.0", + "0.18.0", + "0.19.0", + "0.20.0", + "1.0.0-RC1", + "1.0.0-RC2", + "1.0.0-RC3", + "1.0.0", + "1.0.1", + "1.1.0", + "1.2.0", + "1.3.0", + "1.4.0", + "1.4.1", + "1.5.0", + "1.6.0", + "1.6.1", + "1.6.2", + "1.6.3", + "1.7.0", + "1.8.0", + "1.9.0", + "1.10.0", + "1.11.0", + "1.11.1", + "1.11.2", + "1.12.0", + "1.13.0", + "1.14.0", + "1.15.0-rc.1", + "1.15.0-rc.2", + "1.15.0", + "1.15.1", + "1.16.0-rc.1", + "1.16.0", + "1.17.0", + "1.18.0", + "1.19.0-rc.1", + "1.19.0" + ] + }, + { + "offset": 24, + "versions": [ + "1.20.0", + "1.21.0", + "1.22.0", + "1.23.0-rc.1", + "1.23.0", + "1.23.1", + "1.24.0", + "1.25.0", + "1.26.0", + "1.27.0", + "1.28.0" + ] + } + ] } ] } diff --git a/internal/pkg/instrumentation/bpf/database/sql/probe.go b/internal/pkg/instrumentation/bpf/database/sql/probe.go index 7c2c877a7..03a45f9b5 100644 --- a/internal/pkg/instrumentation/bpf/database/sql/probe.go +++ b/internal/pkg/instrumentation/bpf/database/sql/probe.go @@ -103,6 +103,7 @@ func convertEvent(e *event) []*probe.SpanEvent { semconv.DBQueryText(query), }, ParentSpanContext: pscPtr, + TracerSchema: semconv.SchemaURL, }, } } diff --git a/internal/pkg/instrumentation/bpf/database/sql/probe_test.go b/internal/pkg/instrumentation/bpf/database/sql/probe_test.go index 5ed9d8e18..57a2cdb98 100644 --- a/internal/pkg/instrumentation/bpf/database/sql/probe_test.go +++ b/internal/pkg/instrumentation/bpf/database/sql/probe_test.go @@ -47,6 +47,7 @@ func TestProbeConvertEvent(t *testing.T) { Attributes: []attribute.KeyValue{ semconv.DBQueryText("SELECT * FROM foo"), }, + TracerSchema: semconv.SchemaURL, } assert.Equal(t, want, got[0]) } diff --git a/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/consumer/probe.go b/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/consumer/probe.go index f84caafd5..980e7509b 100644 --- a/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/consumer/probe.go +++ b/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/consumer/probe.go @@ -127,6 +127,7 @@ func convertEvent(e *event) []*probe.SpanEvent { SpanContext: &sc, ParentSpanContext: pscPtr, Attributes: attributes, + TracerSchema: semconv.SchemaURL, }, } } diff --git a/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/consumer/probe_test.go b/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/consumer/probe_test.go index 38e3cb84d..30f5d4cfc 100644 --- a/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/consumer/probe_test.go +++ b/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/consumer/probe_test.go @@ -59,6 +59,7 @@ func TestProbeConvertEvent(t *testing.T) { semconv.MessagingKafkaMessageKey("key1"), semconv.MessagingKafkaConsumerGroup("test consumer group"), }, + TracerSchema: semconv.SchemaURL, } assert.Equal(t, want, got[0]) } diff --git a/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/producer/probe.go b/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/producer/probe.go index a85b058be..863eed88a 100644 --- a/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/producer/probe.go +++ b/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/producer/probe.go @@ -143,6 +143,7 @@ func convertEvent(e *event) []*probe.SpanEvent { SpanContext: &sc, Attributes: msgAttrs, ParentSpanContext: pscPtr, + TracerSchema: semconv.SchemaURL, }) } diff --git a/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/producer/probe_test.go b/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/producer/probe_test.go index 957baa40f..45d1623cc 100644 --- a/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/producer/probe_test.go +++ b/internal/pkg/instrumentation/bpf/github.com/segmentio/kafka-go/producer/probe_test.go @@ -73,6 +73,7 @@ func TestProbeConvertEvent(t *testing.T) { semconv.MessagingOperationTypePublish, semconv.MessagingBatchMessageCount(2), }, + TracerSchema: semconv.SchemaURL, } want2 := &probe.SpanEvent{ @@ -87,6 +88,7 @@ func TestProbeConvertEvent(t *testing.T) { semconv.MessagingOperationTypePublish, semconv.MessagingBatchMessageCount(2), }, + TracerSchema: semconv.SchemaURL, } assert.Equal(t, want1, got[0]) assert.Equal(t, want2, got[1]) diff --git a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf/probe.bpf.c b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf/probe.bpf.c index d60af651f..6e2855ebc 100644 --- a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf/probe.bpf.c +++ b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf/probe.bpf.c @@ -26,6 +26,12 @@ char __license[] SEC("license") = "Dual MIT/GPL"; #define MAX_CONCURRENT 50 #define MAX_SPAN_NAME_LEN 64 #define MAX_STATUS_DESCRIPTION_LEN 64 +#define MAX_TRACER_NAME_LEN 128 +#define MAX_TRACER_VERSION_LEN 32 +#define MAX_TRACER_SCHEMA_URL_LEN 128 + +#define MAX_BUCKETS 8 +#define MAX_TRACERS 64 struct span_description_t { char buf[MAX_STATUS_DESCRIPTION_LEN]; @@ -40,13 +46,37 @@ struct span_name_t { char buf[MAX_SPAN_NAME_LEN]; }; +typedef struct tracer_id { + char name[MAX_TRACER_NAME_LEN]; + char version[MAX_TRACER_VERSION_LEN]; + char schema_url[MAX_TRACER_SCHEMA_URL_LEN]; +} tracer_id_t; + struct otel_span_t { BASE_SPAN_PROPERTIES struct span_name_t span_name; otel_status_t status; otel_attributes_t attributes; + tracer_id_t tracer_id; }; +typedef struct go_tracer_id_partial { + struct go_string name; + struct go_string version; +} go_tracer_id_partial_t; + +typedef struct go_tracer_id_full { + struct go_string name; + struct go_string version; + struct go_string schema_url; +} go_tracer_id_full_t; + +typedef void* go_tracer_ptr; + +// tracerProvider contains a map of tracers +MAP_BUCKET_DEFINITION(go_tracer_id_partial_t, go_tracer_ptr) +MAP_BUCKET_DEFINITION(go_tracer_id_full_t, go_tracer_ptr) + struct { __uint(type, BPF_MAP_TYPE_HASH); __type(key, void*); @@ -61,6 +91,13 @@ struct { __uint(max_entries, MAX_CONCURRENT); } span_name_by_context SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, void*); + __type(value, tracer_id_t); + __uint(max_entries, MAX_CONCURRENT); +} tracer_id_by_context SEC(".maps"); + struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); @@ -69,8 +106,40 @@ struct __uint(max_entries, 2); } otel_span_storage_map SEC(".maps"); +struct +{ + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(key_size, sizeof(u32)); + __uint(value_size, sizeof(MAP_BUCKET_TYPE(go_tracer_id_full_t, go_tracer_ptr))); + __uint(max_entries, 1); +} golang_mapbucket_storage_map SEC(".maps"); + +struct +{ + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(key_size, sizeof(u32)); + __uint(value_size, sizeof(tracer_id_t)); + __uint(max_entries, 1); +} tracer_id_storage_map SEC(".maps"); + + +struct +{ + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, void*); + __type(value, tracer_id_t); + __uint(max_entries, MAX_TRACERS); +} tracer_ptr_to_id_map SEC(".maps"); + + // Injected in init volatile const u64 tracer_delegate_pos; +volatile const u64 tracer_name_pos; +volatile const u64 tracer_provider_pos; +volatile const u64 tracer_provider_tracers_pos; +volatile const u64 buckets_ptr_pos; + +volatile const bool tracer_id_contains_schemaURL; // read_span_name reads the span name from the provided span_name_ptr and stores the result in // span_name.buf. @@ -79,6 +148,173 @@ static __always_inline void read_span_name(struct span_name_t *span_name, const bpf_probe_read(span_name->buf, span_name_size, span_name_ptr); } +static __always_inline long fill_partial_tracer_id_from_tracers_map(void *tracers_map, go_tracer_ptr tracer, tracer_id_t *tracer_id) { + u64 tracers_count = 0; + long res = 0; + res = bpf_probe_read(&tracers_count, sizeof(tracers_count), tracers_map); + if (res < 0) + { + return -1; + } + if (tracers_count == 0) + { + return -1; + } + unsigned char log_2_bucket_count; + res = bpf_probe_read(&log_2_bucket_count, sizeof(log_2_bucket_count), tracers_map + 9); + if (res < 0) + { + return -1; + } + u64 bucket_count = 1 << log_2_bucket_count; + void *buckets_array; + res = bpf_probe_read(&buckets_array, sizeof(buckets_array), (void*)(tracers_map + buckets_ptr_pos)); + if (res < 0) + { + return -1; + } + u32 map_id = 0; + MAP_BUCKET_TYPE(go_tracer_id_partial_t, go_tracer_ptr) *map_bucket = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id); + if (!map_bucket) + { + return -1; + } + + for (u64 j = 0; j < MAX_BUCKETS; j++) + { + if (j >= bucket_count) + { + break; + } + res = bpf_probe_read(map_bucket, sizeof(MAP_BUCKET_TYPE(go_tracer_id_partial_t, go_tracer_ptr)), buckets_array + (j * sizeof(MAP_BUCKET_TYPE(go_tracer_id_partial_t, go_tracer_ptr)))); + if (res < 0) + { + continue; + } + for (u64 i = 0; i < 8; i++) + { + if (map_bucket->tophash[i] == 0) + { + continue; + } + if (map_bucket->values[i] == NULL) + { + continue; + } + if (map_bucket->values[i] != tracer) + { + continue; + } + get_go_string_from_user_ptr(&map_bucket->keys[i].version, tracer_id->version, MAX_TRACER_VERSION_LEN); + return 0; + } + } + return 0; +} + +static __always_inline long fill_full_tracer_id_from_tracers_map(void *tracers_map, go_tracer_ptr tracer, tracer_id_t *tracer_id) { + u64 tracers_count = 0; + long res = 0; + res = bpf_probe_read(&tracers_count, sizeof(tracers_count), tracers_map); + if (res < 0) + { + return -1; + } + if (tracers_count == 0) + { + return -1; + } + unsigned char log_2_bucket_count; + res = bpf_probe_read(&log_2_bucket_count, sizeof(log_2_bucket_count), tracers_map + 9); + if (res < 0) + { + return -1; + } + u64 bucket_count = 1 << log_2_bucket_count; + void *buckets_array; + res = bpf_probe_read(&buckets_array, sizeof(buckets_array), (void*)(tracers_map + buckets_ptr_pos)); + if (res < 0) + { + return -1; + } + u32 map_id = 0; + MAP_BUCKET_TYPE(go_tracer_id_full_t, go_tracer_ptr) *map_bucket = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id); + if (!map_bucket) + { + return -1; + } + + for (u64 j = 0; j < MAX_BUCKETS; j++) + { + if (j >= bucket_count) + { + break; + } + res = bpf_probe_read(map_bucket, sizeof(MAP_BUCKET_TYPE(go_tracer_id_full_t, go_tracer_ptr)), buckets_array + (j * sizeof(MAP_BUCKET_TYPE(go_tracer_id_full_t, go_tracer_ptr)))); + if (res < 0) + { + continue; + } + for (u64 i = 0; i < 8; i++) + { + if (map_bucket->tophash[i] == 0) + { + continue; + } + if (map_bucket->values[i] == NULL) + { + continue; + } + if (map_bucket->values[i] != tracer) + { + continue; + } + get_go_string_from_user_ptr(&map_bucket->keys[i].version, tracer_id->version, MAX_TRACER_VERSION_LEN); + get_go_string_from_user_ptr(&map_bucket->keys[i].schema_url, tracer_id->schema_url, MAX_TRACER_SCHEMA_URL_LEN); + return 0; + } + } + return 0; +} + +static __always_inline long fill_tracer_id(tracer_id_t *tracer_id, go_tracer_ptr tracer) { + // Check if the tracer id is already cached + tracer_id_t *cached_tracer_id = bpf_map_lookup_elem(&tracer_ptr_to_id_map, &tracer); + if (cached_tracer_id != NULL) { + *tracer_id = *cached_tracer_id; + return 0; + } + + if (!get_go_string_from_user_ptr((void*)(tracer + tracer_name_pos), tracer_id->name, MAX_TRACER_NAME_LEN)) { + return -1; + } + + long res = 0; + void *tracer_provider = NULL; + res = bpf_probe_read(&tracer_provider, sizeof(tracer_provider), (void*)(tracer + tracer_provider_pos)); + if (res < 0) { + return res; + } + + void *tracers_map = NULL; + res = bpf_probe_read(&tracers_map, sizeof(tracers_map), (void*)(tracer_provider + tracer_provider_tracers_pos)); + if (res < 0) { + return res; + } + + if (tracer_id_contains_schemaURL) { + res = fill_full_tracer_id_from_tracers_map(tracers_map, tracer, tracer_id); + } else { + res = fill_partial_tracer_id_from_tracers_map(tracers_map, tracer, tracer_id); + } + if (res < 0) { + return res; + } + + bpf_map_update_elem(&tracer_ptr_to_id_map, &tracer, tracer_id, 0); + return 0; +} + // This instrumentation attaches uprobe to the following function: // func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) // https://github.com/open-telemetry/opentelemetry-go/blob/98b32a6c3a87fbee5d34c063b9096f416b250897/internal/global/trace.go#L149 @@ -102,6 +338,20 @@ int uprobe_Start(struct pt_regs *ctx) { void *context_ptr_val = get_Go_context(ctx, 3, 0, true); void *key = get_consistent_key(ctx, context_ptr_val); bpf_map_update_elem(&span_name_by_context, &key, &span_name, 0); + + // Get the tracer id + u32 map_id = 0; + tracer_id_t *tracer_id = bpf_map_lookup_elem(&tracer_id_storage_map, &map_id); + if (tracer_id == NULL) { + return 0; + } + __builtin_memset(tracer_id, 0, sizeof(tracer_id_t)); + + long res = fill_tracer_id(tracer_id, tracer_ptr); + if (res < 0) { + return 0; + } + bpf_map_update_elem(&tracer_id_by_context, &key, tracer_id, 0); return 0; } @@ -118,6 +368,11 @@ int uprobe_Start_Returns(struct pt_regs *ctx) { return 0; } + tracer_id_t *tracer_id = bpf_map_lookup_elem(&tracer_id_by_context, &key); + if (tracer_id == NULL) { + goto done_without_tracer_id; + } + u32 zero_span_key = 0; struct otel_span_t *zero_span = bpf_map_lookup_elem(&otel_span_storage_map, &zero_span_key); if (zero_span == NULL) { @@ -134,7 +389,8 @@ int uprobe_Start_Returns(struct pt_regs *ctx) { } otel_span->start_time = bpf_ktime_get_ns(); - copy_byte_arrays((unsigned char*)span_name->buf, (unsigned char*)otel_span->span_name.buf, MAX_SPAN_NAME_LEN); + otel_span->span_name = *span_name; + otel_span->tracer_id = *tracer_id; // Get the ** returned ** context and Span (concrete type of the interfaces) void *ret_context_ptr_val = get_argument(ctx, 2); @@ -153,6 +409,8 @@ int uprobe_Start_Returns(struct pt_regs *ctx) { start_tracking_span(ret_context_ptr_val, &otel_span->sc); done: + bpf_map_delete_elem(&tracer_id_by_context, &key); +done_without_tracer_id: bpf_map_delete_elem(&span_name_by_context, &key); return 0; } diff --git a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf_arm64_bpfel.go b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf_arm64_bpfel.go index f36e9c00a..e498d18b8 100644 --- a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf_arm64_bpfel.go +++ b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf_arm64_bpfel.go @@ -32,7 +32,8 @@ type bpfOtelSpanT struct { } ValidAttrs uint8 } - _ [3]byte + TracerId bpfTracerIdT + _ [3]byte } type bpfSliceArrayBuff struct{ Buff [1024]uint8 } @@ -46,6 +47,12 @@ type bpfSpanContext struct { type bpfSpanNameT struct{ Buf [64]int8 } +type bpfTracerIdT struct { + Name [128]int8 + Version [32]int8 + SchemaUrl [128]int8 +} + // loadBpf returns the embedded CollectionSpec for bpf. func loadBpf() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_BpfBytes) @@ -99,14 +106,18 @@ type bpfProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type bpfMapSpecs struct { - ActiveSpansBySpanPtr *ebpf.MapSpec `ebpf:"active_spans_by_span_ptr"` - AllocMap *ebpf.MapSpec `ebpf:"alloc_map"` - Events *ebpf.MapSpec `ebpf:"events"` - OtelSpanStorageMap *ebpf.MapSpec `ebpf:"otel_span_storage_map"` - SliceArrayBuffMap *ebpf.MapSpec `ebpf:"slice_array_buff_map"` - SpanNameByContext *ebpf.MapSpec `ebpf:"span_name_by_context"` - TrackedSpans *ebpf.MapSpec `ebpf:"tracked_spans"` - TrackedSpansBySc *ebpf.MapSpec `ebpf:"tracked_spans_by_sc"` + ActiveSpansBySpanPtr *ebpf.MapSpec `ebpf:"active_spans_by_span_ptr"` + AllocMap *ebpf.MapSpec `ebpf:"alloc_map"` + Events *ebpf.MapSpec `ebpf:"events"` + GolangMapbucketStorageMap *ebpf.MapSpec `ebpf:"golang_mapbucket_storage_map"` + OtelSpanStorageMap *ebpf.MapSpec `ebpf:"otel_span_storage_map"` + SliceArrayBuffMap *ebpf.MapSpec `ebpf:"slice_array_buff_map"` + SpanNameByContext *ebpf.MapSpec `ebpf:"span_name_by_context"` + TracerIdByContext *ebpf.MapSpec `ebpf:"tracer_id_by_context"` + TracerIdStorageMap *ebpf.MapSpec `ebpf:"tracer_id_storage_map"` + TracerPtrToIdMap *ebpf.MapSpec `ebpf:"tracer_ptr_to_id_map"` + TrackedSpans *ebpf.MapSpec `ebpf:"tracked_spans"` + TrackedSpansBySc *ebpf.MapSpec `ebpf:"tracked_spans_by_sc"` } // bpfObjects contains all objects after they have been loaded into the kernel. @@ -128,14 +139,18 @@ func (o *bpfObjects) Close() error { // // It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. type bpfMaps struct { - ActiveSpansBySpanPtr *ebpf.Map `ebpf:"active_spans_by_span_ptr"` - AllocMap *ebpf.Map `ebpf:"alloc_map"` - Events *ebpf.Map `ebpf:"events"` - OtelSpanStorageMap *ebpf.Map `ebpf:"otel_span_storage_map"` - SliceArrayBuffMap *ebpf.Map `ebpf:"slice_array_buff_map"` - SpanNameByContext *ebpf.Map `ebpf:"span_name_by_context"` - TrackedSpans *ebpf.Map `ebpf:"tracked_spans"` - TrackedSpansBySc *ebpf.Map `ebpf:"tracked_spans_by_sc"` + ActiveSpansBySpanPtr *ebpf.Map `ebpf:"active_spans_by_span_ptr"` + AllocMap *ebpf.Map `ebpf:"alloc_map"` + Events *ebpf.Map `ebpf:"events"` + GolangMapbucketStorageMap *ebpf.Map `ebpf:"golang_mapbucket_storage_map"` + OtelSpanStorageMap *ebpf.Map `ebpf:"otel_span_storage_map"` + SliceArrayBuffMap *ebpf.Map `ebpf:"slice_array_buff_map"` + SpanNameByContext *ebpf.Map `ebpf:"span_name_by_context"` + TracerIdByContext *ebpf.Map `ebpf:"tracer_id_by_context"` + TracerIdStorageMap *ebpf.Map `ebpf:"tracer_id_storage_map"` + TracerPtrToIdMap *ebpf.Map `ebpf:"tracer_ptr_to_id_map"` + TrackedSpans *ebpf.Map `ebpf:"tracked_spans"` + TrackedSpansBySc *ebpf.Map `ebpf:"tracked_spans_by_sc"` } func (m *bpfMaps) Close() error { @@ -143,9 +158,13 @@ func (m *bpfMaps) Close() error { m.ActiveSpansBySpanPtr, m.AllocMap, m.Events, + m.GolangMapbucketStorageMap, m.OtelSpanStorageMap, m.SliceArrayBuffMap, m.SpanNameByContext, + m.TracerIdByContext, + m.TracerIdStorageMap, + m.TracerPtrToIdMap, m.TrackedSpans, m.TrackedSpansBySc, ) diff --git a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf_x86_bpfel.go b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf_x86_bpfel.go index 34026c226..3e2beecc3 100644 --- a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf_x86_bpfel.go +++ b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/bpf_x86_bpfel.go @@ -32,7 +32,8 @@ type bpfOtelSpanT struct { } ValidAttrs uint8 } - _ [3]byte + TracerId bpfTracerIdT + _ [3]byte } type bpfSliceArrayBuff struct{ Buff [1024]uint8 } @@ -46,6 +47,12 @@ type bpfSpanContext struct { type bpfSpanNameT struct{ Buf [64]int8 } +type bpfTracerIdT struct { + Name [128]int8 + Version [32]int8 + SchemaUrl [128]int8 +} + // loadBpf returns the embedded CollectionSpec for bpf. func loadBpf() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_BpfBytes) @@ -99,14 +106,18 @@ type bpfProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type bpfMapSpecs struct { - ActiveSpansBySpanPtr *ebpf.MapSpec `ebpf:"active_spans_by_span_ptr"` - AllocMap *ebpf.MapSpec `ebpf:"alloc_map"` - Events *ebpf.MapSpec `ebpf:"events"` - OtelSpanStorageMap *ebpf.MapSpec `ebpf:"otel_span_storage_map"` - SliceArrayBuffMap *ebpf.MapSpec `ebpf:"slice_array_buff_map"` - SpanNameByContext *ebpf.MapSpec `ebpf:"span_name_by_context"` - TrackedSpans *ebpf.MapSpec `ebpf:"tracked_spans"` - TrackedSpansBySc *ebpf.MapSpec `ebpf:"tracked_spans_by_sc"` + ActiveSpansBySpanPtr *ebpf.MapSpec `ebpf:"active_spans_by_span_ptr"` + AllocMap *ebpf.MapSpec `ebpf:"alloc_map"` + Events *ebpf.MapSpec `ebpf:"events"` + GolangMapbucketStorageMap *ebpf.MapSpec `ebpf:"golang_mapbucket_storage_map"` + OtelSpanStorageMap *ebpf.MapSpec `ebpf:"otel_span_storage_map"` + SliceArrayBuffMap *ebpf.MapSpec `ebpf:"slice_array_buff_map"` + SpanNameByContext *ebpf.MapSpec `ebpf:"span_name_by_context"` + TracerIdByContext *ebpf.MapSpec `ebpf:"tracer_id_by_context"` + TracerIdStorageMap *ebpf.MapSpec `ebpf:"tracer_id_storage_map"` + TracerPtrToIdMap *ebpf.MapSpec `ebpf:"tracer_ptr_to_id_map"` + TrackedSpans *ebpf.MapSpec `ebpf:"tracked_spans"` + TrackedSpansBySc *ebpf.MapSpec `ebpf:"tracked_spans_by_sc"` } // bpfObjects contains all objects after they have been loaded into the kernel. @@ -128,14 +139,18 @@ func (o *bpfObjects) Close() error { // // It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. type bpfMaps struct { - ActiveSpansBySpanPtr *ebpf.Map `ebpf:"active_spans_by_span_ptr"` - AllocMap *ebpf.Map `ebpf:"alloc_map"` - Events *ebpf.Map `ebpf:"events"` - OtelSpanStorageMap *ebpf.Map `ebpf:"otel_span_storage_map"` - SliceArrayBuffMap *ebpf.Map `ebpf:"slice_array_buff_map"` - SpanNameByContext *ebpf.Map `ebpf:"span_name_by_context"` - TrackedSpans *ebpf.Map `ebpf:"tracked_spans"` - TrackedSpansBySc *ebpf.Map `ebpf:"tracked_spans_by_sc"` + ActiveSpansBySpanPtr *ebpf.Map `ebpf:"active_spans_by_span_ptr"` + AllocMap *ebpf.Map `ebpf:"alloc_map"` + Events *ebpf.Map `ebpf:"events"` + GolangMapbucketStorageMap *ebpf.Map `ebpf:"golang_mapbucket_storage_map"` + OtelSpanStorageMap *ebpf.Map `ebpf:"otel_span_storage_map"` + SliceArrayBuffMap *ebpf.Map `ebpf:"slice_array_buff_map"` + SpanNameByContext *ebpf.Map `ebpf:"span_name_by_context"` + TracerIdByContext *ebpf.Map `ebpf:"tracer_id_by_context"` + TracerIdStorageMap *ebpf.Map `ebpf:"tracer_id_storage_map"` + TracerPtrToIdMap *ebpf.Map `ebpf:"tracer_ptr_to_id_map"` + TrackedSpans *ebpf.Map `ebpf:"tracked_spans"` + TrackedSpansBySc *ebpf.Map `ebpf:"tracked_spans_by_sc"` } func (m *bpfMaps) Close() error { @@ -143,9 +158,13 @@ func (m *bpfMaps) Close() error { m.ActiveSpansBySpanPtr, m.AllocMap, m.Events, + m.GolangMapbucketStorageMap, m.OtelSpanStorageMap, m.SliceArrayBuffMap, m.SpanNameByContext, + m.TracerIdByContext, + m.TracerIdStorageMap, + m.TracerPtrToIdMap, m.TrackedSpans, m.TrackedSpansBySc, ) diff --git a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go index 99744ea7f..4bbed87bc 100644 --- a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go +++ b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe.go @@ -5,12 +5,16 @@ package global import ( "encoding/binary" + "fmt" "math" + "go.opentelemetry.io/auto/internal/pkg/inject" "go.opentelemetry.io/auto/internal/pkg/instrumentation/probe" + "go.opentelemetry.io/auto/internal/pkg/process" "go.opentelemetry.io/auto/internal/pkg/structfield" "github.com/go-logr/logr" + "github.com/hashicorp/go-version" "golang.org/x/sys/unix" "go.opentelemetry.io/otel/attribute" @@ -79,6 +83,23 @@ func New(logger logr.Logger) probe.Probe { Key: "tracer_delegate_pos", Val: structfield.NewID("go.opentelemetry.io/otel", "go.opentelemetry.io/otel/internal/global", "tracer", "delegate"), }, + probe.StructFieldConst{ + Key: "tracer_name_pos", + Val: structfield.NewID("go.opentelemetry.io/otel", "go.opentelemetry.io/otel/internal/global", "tracer", "name"), + }, + probe.StructFieldConst{ + Key: "tracer_provider_pos", + Val: structfield.NewID("go.opentelemetry.io/otel", "go.opentelemetry.io/otel/internal/global", "tracer", "provider"), + }, + probe.StructFieldConst{ + Key: "tracer_provider_tracers_pos", + Val: structfield.NewID("go.opentelemetry.io/otel", "go.opentelemetry.io/otel/internal/global", "tracerProvider", "tracers"), + }, + probe.StructFieldConst{ + Key: "buckets_ptr_pos", + Val: structfield.NewID("std", "runtime", "hmap", "buckets"), + }, + tracerIDContainsSchemaURL{}, }, Uprobes: []probe.Uprobe{ { @@ -111,6 +132,23 @@ func New(logger logr.Logger) probe.Probe { } } +// framePosConst is a Probe Const defining whether the tracer key contains schemaURL. +type tracerIDContainsSchemaURL struct{} + +// Prior to v1.28 the tracer key did not contain schemaURL. However, in that version a +// change was made to include it. +// https://github.com/open-telemetry/opentelemetry-go/pull/5426/files +var paramChangeVer = version.Must(version.NewVersion("1.28.0")) + +func (c tracerIDContainsSchemaURL) InjectOption(td *process.TargetDetails) (inject.Option, error) { + ver, ok := td.Libraries["go.opentelemetry.io/otel"] + if !ok { + return nil, fmt.Errorf("unknown module version: %s", pkg) + } + + return inject.WithKeyValue("tracer_id_contains_schemaURL", ver.GreaterThanOrEqual(paramChangeVer)), nil +} + type attributeKeyVal struct { ValLength uint16 Vtype uint8 @@ -129,12 +167,19 @@ type status struct { Description [64]byte } +type tracerID struct { + Name [128]byte + Version [32]byte + SchemaURL [128]byte +} + // event represents a manual span created by the user. type event struct { context.BaseSpanProperties SpanName [64]byte Status status Attributes attributesBuffer + TracerID tracerID } func convertEvent(e *event) []*probe.SpanEvent { @@ -171,6 +216,9 @@ func convertEvent(e *event) []*probe.SpanEvent { Code: codes.Code(e.Status.Code), Description: string(unix.ByteSliceToString(e.Status.Description[:])), }, + TracerName: unix.ByteSliceToString(e.TracerID.Name[:]), + TracerVersion: unix.ByteSliceToString(e.TracerID.Version[:]), + TracerSchema: unix.ByteSliceToString(e.TracerID.SchemaURL[:]), }, } } diff --git a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe_test.go b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe_test.go index 01e03619c..a6be025c2 100644 --- a/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe_test.go +++ b/internal/pkg/instrumentation/bpf/go.opentelemetry.io/otel/traceglobal/probe_test.go @@ -87,6 +87,14 @@ func TestProbeConvertEvent(t *testing.T) { }, ValidAttrs: 5, }, + TracerID: tracerID{ + // "user-tracer" + Name: [128]byte{0x75, 0x73, 0x65, 0x72, 0x2d, 0x74, 0x72, 0x61, 0x63, 0x65, 0x72}, + // "v1" + Version: [32]byte{0x76, 0x31}, + // "user-schema" + SchemaURL: [128]byte{0x75, 0x73, 0x65, 0x72, 0x2d, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61}, + }, }) sc := trace.NewSpanContext(trace.SpanContextConfig{ @@ -106,6 +114,9 @@ func TestProbeConvertEvent(t *testing.T) { attribute.Int64("int_key", 42), attribute.String("string_key2", "string value 2"), }, + TracerName: "user-tracer", + TracerVersion: "v1", + TracerSchema: "user-schema", } assert.Equal(t, want, got[0]) } diff --git a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go index 6dac503c5..12bfeaba5 100644 --- a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go +++ b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/client/probe.go @@ -137,6 +137,7 @@ func convertEvent(e *event) []*probe.SpanEvent { Attributes: attrs, SpanContext: &sc, ParentSpanContext: pscPtr, + TracerSchema: semconv.SchemaURL, }, } } diff --git a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go index 3792751ee..9264d125d 100644 --- a/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go +++ b/internal/pkg/instrumentation/bpf/google.golang.org/grpc/server/probe.go @@ -135,6 +135,7 @@ func convertEvent(e *event) []*probe.SpanEvent { }, ParentSpanContext: pscPtr, SpanContext: &sc, + TracerSchema: semconv.SchemaURL, }, } } diff --git a/internal/pkg/instrumentation/bpf/net/http/client/bpf/probe.bpf.c b/internal/pkg/instrumentation/bpf/net/http/client/bpf/probe.bpf.c index b8640afb2..ced118d3a 100644 --- a/internal/pkg/instrumentation/bpf/net/http/client/bpf/probe.bpf.c +++ b/internal/pkg/instrumentation/bpf/net/http/client/bpf/probe.bpf.c @@ -45,13 +45,6 @@ struct { __uint(max_entries, MAX_CONCURRENT); } http_events SEC(".maps"); -struct { - __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); - __uint(key_size, sizeof(u32)); - __uint(value_size, sizeof(struct map_bucket)); - __uint(max_entries, 1); -} golang_mapbucket_storage_map SEC(".maps"); - struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); @@ -73,7 +66,6 @@ volatile const u64 url_ptr_pos; volatile const u64 path_ptr_pos; volatile const u64 headers_ptr_pos; volatile const u64 ctx_ptr_pos; -volatile const u64 buckets_ptr_pos; volatile const u64 status_code_pos; volatile const u64 request_host_pos; volatile const u64 request_proto_pos; diff --git a/internal/pkg/instrumentation/bpf/net/http/client/bpf_arm64_bpfel.go b/internal/pkg/instrumentation/bpf/net/http/client/bpf_arm64_bpfel.go index 62d6e7c2b..a9bb9c41b 100644 --- a/internal/pkg/instrumentation/bpf/net/http/client/bpf_arm64_bpfel.go +++ b/internal/pkg/instrumentation/bpf/net/http/client/bpf_arm64_bpfel.go @@ -95,7 +95,6 @@ type bpfProgramSpecs struct { type bpfMapSpecs struct { AllocMap *ebpf.MapSpec `ebpf:"alloc_map"` Events *ebpf.MapSpec `ebpf:"events"` - GolangMapbucketStorageMap *ebpf.MapSpec `ebpf:"golang_mapbucket_storage_map"` HttpClientUprobeStorageMap *ebpf.MapSpec `ebpf:"http_client_uprobe_storage_map"` HttpEvents *ebpf.MapSpec `ebpf:"http_events"` HttpHeaders *ebpf.MapSpec `ebpf:"http_headers"` @@ -125,7 +124,6 @@ func (o *bpfObjects) Close() error { type bpfMaps struct { AllocMap *ebpf.Map `ebpf:"alloc_map"` Events *ebpf.Map `ebpf:"events"` - GolangMapbucketStorageMap *ebpf.Map `ebpf:"golang_mapbucket_storage_map"` HttpClientUprobeStorageMap *ebpf.Map `ebpf:"http_client_uprobe_storage_map"` HttpEvents *ebpf.Map `ebpf:"http_events"` HttpHeaders *ebpf.Map `ebpf:"http_headers"` @@ -138,7 +136,6 @@ func (m *bpfMaps) Close() error { return _BpfClose( m.AllocMap, m.Events, - m.GolangMapbucketStorageMap, m.HttpClientUprobeStorageMap, m.HttpEvents, m.HttpHeaders, diff --git a/internal/pkg/instrumentation/bpf/net/http/client/bpf_no_tp_arm64_bpfel.go b/internal/pkg/instrumentation/bpf/net/http/client/bpf_no_tp_arm64_bpfel.go index 06294fada..9d35f68f4 100644 --- a/internal/pkg/instrumentation/bpf/net/http/client/bpf_no_tp_arm64_bpfel.go +++ b/internal/pkg/instrumentation/bpf/net/http/client/bpf_no_tp_arm64_bpfel.go @@ -95,7 +95,6 @@ type bpf_no_tpProgramSpecs struct { type bpf_no_tpMapSpecs struct { AllocMap *ebpf.MapSpec `ebpf:"alloc_map"` Events *ebpf.MapSpec `ebpf:"events"` - GolangMapbucketStorageMap *ebpf.MapSpec `ebpf:"golang_mapbucket_storage_map"` HttpClientUprobeStorageMap *ebpf.MapSpec `ebpf:"http_client_uprobe_storage_map"` HttpEvents *ebpf.MapSpec `ebpf:"http_events"` HttpHeaders *ebpf.MapSpec `ebpf:"http_headers"` @@ -125,7 +124,6 @@ func (o *bpf_no_tpObjects) Close() error { type bpf_no_tpMaps struct { AllocMap *ebpf.Map `ebpf:"alloc_map"` Events *ebpf.Map `ebpf:"events"` - GolangMapbucketStorageMap *ebpf.Map `ebpf:"golang_mapbucket_storage_map"` HttpClientUprobeStorageMap *ebpf.Map `ebpf:"http_client_uprobe_storage_map"` HttpEvents *ebpf.Map `ebpf:"http_events"` HttpHeaders *ebpf.Map `ebpf:"http_headers"` @@ -138,7 +136,6 @@ func (m *bpf_no_tpMaps) Close() error { return _Bpf_no_tpClose( m.AllocMap, m.Events, - m.GolangMapbucketStorageMap, m.HttpClientUprobeStorageMap, m.HttpEvents, m.HttpHeaders, diff --git a/internal/pkg/instrumentation/bpf/net/http/client/bpf_no_tp_x86_bpfel.go b/internal/pkg/instrumentation/bpf/net/http/client/bpf_no_tp_x86_bpfel.go index 9157b67fd..db6cf826d 100644 --- a/internal/pkg/instrumentation/bpf/net/http/client/bpf_no_tp_x86_bpfel.go +++ b/internal/pkg/instrumentation/bpf/net/http/client/bpf_no_tp_x86_bpfel.go @@ -95,7 +95,6 @@ type bpf_no_tpProgramSpecs struct { type bpf_no_tpMapSpecs struct { AllocMap *ebpf.MapSpec `ebpf:"alloc_map"` Events *ebpf.MapSpec `ebpf:"events"` - GolangMapbucketStorageMap *ebpf.MapSpec `ebpf:"golang_mapbucket_storage_map"` HttpClientUprobeStorageMap *ebpf.MapSpec `ebpf:"http_client_uprobe_storage_map"` HttpEvents *ebpf.MapSpec `ebpf:"http_events"` HttpHeaders *ebpf.MapSpec `ebpf:"http_headers"` @@ -125,7 +124,6 @@ func (o *bpf_no_tpObjects) Close() error { type bpf_no_tpMaps struct { AllocMap *ebpf.Map `ebpf:"alloc_map"` Events *ebpf.Map `ebpf:"events"` - GolangMapbucketStorageMap *ebpf.Map `ebpf:"golang_mapbucket_storage_map"` HttpClientUprobeStorageMap *ebpf.Map `ebpf:"http_client_uprobe_storage_map"` HttpEvents *ebpf.Map `ebpf:"http_events"` HttpHeaders *ebpf.Map `ebpf:"http_headers"` @@ -138,7 +136,6 @@ func (m *bpf_no_tpMaps) Close() error { return _Bpf_no_tpClose( m.AllocMap, m.Events, - m.GolangMapbucketStorageMap, m.HttpClientUprobeStorageMap, m.HttpEvents, m.HttpHeaders, diff --git a/internal/pkg/instrumentation/bpf/net/http/client/bpf_x86_bpfel.go b/internal/pkg/instrumentation/bpf/net/http/client/bpf_x86_bpfel.go index 206215330..ff925241e 100644 --- a/internal/pkg/instrumentation/bpf/net/http/client/bpf_x86_bpfel.go +++ b/internal/pkg/instrumentation/bpf/net/http/client/bpf_x86_bpfel.go @@ -95,7 +95,6 @@ type bpfProgramSpecs struct { type bpfMapSpecs struct { AllocMap *ebpf.MapSpec `ebpf:"alloc_map"` Events *ebpf.MapSpec `ebpf:"events"` - GolangMapbucketStorageMap *ebpf.MapSpec `ebpf:"golang_mapbucket_storage_map"` HttpClientUprobeStorageMap *ebpf.MapSpec `ebpf:"http_client_uprobe_storage_map"` HttpEvents *ebpf.MapSpec `ebpf:"http_events"` HttpHeaders *ebpf.MapSpec `ebpf:"http_headers"` @@ -125,7 +124,6 @@ func (o *bpfObjects) Close() error { type bpfMaps struct { AllocMap *ebpf.Map `ebpf:"alloc_map"` Events *ebpf.Map `ebpf:"events"` - GolangMapbucketStorageMap *ebpf.Map `ebpf:"golang_mapbucket_storage_map"` HttpClientUprobeStorageMap *ebpf.Map `ebpf:"http_client_uprobe_storage_map"` HttpEvents *ebpf.Map `ebpf:"http_events"` HttpHeaders *ebpf.Map `ebpf:"http_headers"` @@ -138,7 +136,6 @@ func (m *bpfMaps) Close() error { return _BpfClose( m.AllocMap, m.Events, - m.GolangMapbucketStorageMap, m.HttpClientUprobeStorageMap, m.HttpEvents, m.HttpHeaders, diff --git a/internal/pkg/instrumentation/bpf/net/http/client/probe.go b/internal/pkg/instrumentation/bpf/net/http/client/probe.go index 75d6c09a7..f7eb679e7 100644 --- a/internal/pkg/instrumentation/bpf/net/http/client/probe.go +++ b/internal/pkg/instrumentation/bpf/net/http/client/probe.go @@ -92,10 +92,6 @@ func New(logger logr.Logger) probe.Probe { Key: "status_code_pos", Val: structfield.NewID("std", "net/http", "Response", "StatusCode"), }, - probe.StructFieldConst{ - Key: "buckets_ptr_pos", - Val: structfield.NewID("std", "runtime", "hmap", "buckets"), - }, probe.StructFieldConst{ Key: "request_host_pos", Val: structfield.NewID("std", "net/http", "Request", "Host"), @@ -283,6 +279,7 @@ func convertEvent(e *event) []*probe.SpanEvent { SpanContext: &sc, Attributes: attrs, ParentSpanContext: pscPtr, + TracerSchema: semconv.SchemaURL, } if int(e.StatusCode) >= 400 && int(e.StatusCode) < 600 { diff --git a/internal/pkg/instrumentation/bpf/net/http/client/probe_test.go b/internal/pkg/instrumentation/bpf/net/http/client/probe_test.go index 0a7dc3630..9369b62c6 100644 --- a/internal/pkg/instrumentation/bpf/net/http/client/probe_test.go +++ b/internal/pkg/instrumentation/bpf/net/http/client/probe_test.go @@ -106,6 +106,7 @@ func TestConvertEvent(t *testing.T) { semconv.ServerAddress(hostString), semconv.NetworkProtocolVersion("1.1"), }, + TracerSchema: semconv.SchemaURL, }, }, }, @@ -138,7 +139,8 @@ func TestConvertEvent(t *testing.T) { semconv.ServerAddress(hostString), semconv.NetworkProtocolVersion("1.1"), }, - Status: probe.Status{Code: codes.Error}, + Status: probe.Status{Code: codes.Error}, + TracerSchema: semconv.SchemaURL, }, }, }, @@ -171,7 +173,8 @@ func TestConvertEvent(t *testing.T) { semconv.ServerAddress(hostString), semconv.NetworkProtocolVersion("1.1"), }, - Status: probe.Status{Code: codes.Error}, + Status: probe.Status{Code: codes.Error}, + TracerSchema: semconv.SchemaURL, }, }, }, @@ -205,6 +208,7 @@ func TestConvertEvent(t *testing.T) { semconv.NetworkProtocolName("foo"), semconv.NetworkProtocolVersion("2.2"), }, + TracerSchema: semconv.SchemaURL, }, }, }, @@ -240,6 +244,7 @@ func TestConvertEvent(t *testing.T) { semconv.ServerAddress(hostString), semconv.NetworkProtocolVersion("1.1"), }, + TracerSchema: semconv.SchemaURL, }, }, }, @@ -275,6 +280,7 @@ func TestConvertEvent(t *testing.T) { semconv.URLFull("http:/home?"), semconv.NetworkProtocolVersion("1.1"), }, + TracerSchema: semconv.SchemaURL, }, }, }, diff --git a/internal/pkg/instrumentation/bpf/net/http/server/bpf/probe.bpf.c b/internal/pkg/instrumentation/bpf/net/http/server/bpf/probe.bpf.c index 00cc93649..7f949c155 100644 --- a/internal/pkg/instrumentation/bpf/net/http/server/bpf/probe.bpf.c +++ b/internal/pkg/instrumentation/bpf/net/http/server/bpf/probe.bpf.c @@ -50,6 +50,8 @@ struct uprobe_data_t u64 resp_ptr; }; +MAP_BUCKET_DEFINITION(go_string_t, go_slice_t) + struct { __uint(type, BPF_MAP_TYPE_HASH); @@ -62,7 +64,7 @@ struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __uint(key_size, sizeof(u32)); - __uint(value_size, sizeof(struct map_bucket)); + __uint(value_size, sizeof(MAP_BUCKET_TYPE(go_string_t, go_slice_t))); __uint(max_entries, 1); } golang_mapbucket_storage_map SEC(".maps"); @@ -129,7 +131,7 @@ static __always_inline long extract_context_from_req_headers(void *headers_ptr_p return -1; } u32 map_id = 0; - struct map_bucket *map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id); + MAP_BUCKET_TYPE(go_string_t, go_slice_t) *map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id); if (!map_value) { return -1; @@ -141,7 +143,7 @@ static __always_inline long extract_context_from_req_headers(void *headers_ptr_p { break; } - res = bpf_probe_read(map_value, sizeof(struct map_bucket), header_buckets + (j * sizeof(struct map_bucket))); + res = bpf_probe_read(map_value, sizeof(MAP_BUCKET_TYPE(go_string_t, go_slice_t)), header_buckets + (j * sizeof(MAP_BUCKET_TYPE(go_string_t, go_slice_t)))); if (res < 0) { continue; diff --git a/internal/pkg/instrumentation/bpf/net/http/server/probe.go b/internal/pkg/instrumentation/bpf/net/http/server/probe.go index a91063ebc..3996aa770 100644 --- a/internal/pkg/instrumentation/bpf/net/http/server/probe.go +++ b/internal/pkg/instrumentation/bpf/net/http/server/probe.go @@ -216,6 +216,7 @@ func convertEvent(e *event) []*probe.SpanEvent { SpanContext: &sc, ParentSpanContext: pscPtr, Attributes: attributes, + TracerSchema: semconv.SchemaURL, } if int(e.StatusCode) >= 500 && int(e.StatusCode) < 600 { diff --git a/internal/pkg/instrumentation/bpf/net/http/server/probe_test.go b/internal/pkg/instrumentation/bpf/net/http/server/probe_test.go index 18a3c0ab1..bcf50e338 100644 --- a/internal/pkg/instrumentation/bpf/net/http/server/probe_test.go +++ b/internal/pkg/instrumentation/bpf/net/http/server/probe_test.go @@ -71,6 +71,7 @@ func TestProbeConvertEvent(t *testing.T) { semconv.ServerPort(8080), semconv.NetworkProtocolVersion("1.1"), }, + TracerSchema: semconv.SchemaURL, }, }, }, @@ -111,6 +112,7 @@ func TestProbeConvertEvent(t *testing.T) { semconv.NetworkProtocolName("FOO"), semconv.NetworkProtocolVersion("2.2"), }, + TracerSchema: semconv.SchemaURL, }, }, }, @@ -150,6 +152,7 @@ func TestProbeConvertEvent(t *testing.T) { semconv.ServerPort(8080), semconv.NetworkProtocolVersion("1.1"), }, + TracerSchema: semconv.SchemaURL, }, }, }, @@ -189,7 +192,8 @@ func TestProbeConvertEvent(t *testing.T) { semconv.ServerPort(8080), semconv.NetworkProtocolVersion("1.1"), }, - Status: probe.Status{Code: codes.Error}, + Status: probe.Status{Code: codes.Error}, + TracerSchema: semconv.SchemaURL, }, }, }, diff --git a/internal/pkg/instrumentation/probe/event.go b/internal/pkg/instrumentation/probe/event.go index b60f391d6..6e2e48b69 100644 --- a/internal/pkg/instrumentation/probe/event.go +++ b/internal/pkg/instrumentation/probe/event.go @@ -29,4 +29,7 @@ type SpanEvent struct { SpanContext *trace.SpanContext ParentSpanContext *trace.SpanContext Status Status + TracerName string + TracerVersion string + TracerSchema string } diff --git a/internal/pkg/opentelemetry/controller.go b/internal/pkg/opentelemetry/controller.go index ed6141579..66bf53b90 100644 --- a/internal/pkg/opentelemetry/controller.go +++ b/internal/pkg/opentelemetry/controller.go @@ -19,21 +19,37 @@ type Controller struct { logger logr.Logger version string tracerProvider trace.TracerProvider - tracersMap map[string]trace.Tracer + tracersMap map[tracerID]trace.Tracer bootTime int64 } -func (c *Controller) getTracer(pkg string) trace.Tracer { - t, exists := c.tracersMap[pkg] +type tracerID struct{ name, version, schema string } + +func (c *Controller) getTracer(pkg, tracerName, version, schema string) trace.Tracer { + // Default Tracer ID, if the user does not provide one. + tID := tracerID{name: pkg, version: c.version} + if tracerName != "" { + tID = tracerID{name: tracerName, version: version, schema: schema} + } + + t, exists := c.tracersMap[tID] if exists { return t } - newTracer := c.tracerProvider.Tracer( - "go.opentelemetry.io/auto/"+pkg, - trace.WithInstrumentationVersion(c.version), - ) - c.tracersMap[pkg] = newTracer + var newTracer trace.Tracer + if tracerName != "" { + // If the user has provided a tracer, use it. + newTracer = c.tracerProvider.Tracer(tracerName, trace.WithInstrumentationVersion(version), trace.WithSchemaURL(schema)) + } else { + newTracer = c.tracerProvider.Tracer( + "go.opentelemetry.io/auto/"+pkg, + trace.WithInstrumentationVersion(c.version), + trace.WithSchemaURL(schema), + ) + } + + c.tracersMap[tID] = newTracer return newTracer } @@ -54,7 +70,8 @@ func (c *Controller) Trace(event *probe.Event) { } ctx = ContextWithEBPFEvent(ctx, *se) - _, span := c.getTracer(event.Package). + c.logger.V(1).Info("getting tracer", "name", se.TracerName, "version", se.TracerVersion, "schema", se.TracerSchema) + _, span := c.getTracer(event.Package, se.TracerName, se.TracerVersion, se.TracerSchema). Start(ctx, se.SpanName, trace.WithAttributes(se.Attributes...), trace.WithSpanKind(event.Kind), @@ -81,7 +98,7 @@ func NewController(logger logr.Logger, tracerProvider trace.TracerProvider, ver logger: logger, version: ver, tracerProvider: tracerProvider, - tracersMap: make(map[string]trace.Tracer), + tracersMap: make(map[tracerID]trace.Tracer), bootTime: bt, }, nil } diff --git a/internal/pkg/opentelemetry/controller_test.go b/internal/pkg/opentelemetry/controller_test.go index 72743a197..ce8ae2206 100644 --- a/internal/pkg/opentelemetry/controller_test.go +++ b/internal/pkg/opentelemetry/controller_test.go @@ -101,10 +101,11 @@ func TestTrace(t *testing.T) { Kind: trace.SpanKindClient, SpanEvents: []*probe.SpanEvent{ { - SpanName: "testSpan", - StartTime: startTime.Unix(), - EndTime: endTime.Unix(), - SpanContext: &spanContext, + SpanName: "testSpan", + StartTime: startTime.Unix(), + EndTime: endTime.Unix(), + SpanContext: &spanContext, + TracerSchema: semconv.SchemaURL, }, }, }, @@ -116,8 +117,9 @@ func TestTrace(t *testing.T) { EndTime: convertedEndTime, Resource: instResource(), InstrumentationLibrary: instrumentation.Library{ - Name: "go.opentelemetry.io/auto/foo/bar", - Version: "test", + Name: "go.opentelemetry.io/auto/foo/bar", + Version: "test", + SchemaURL: semconv.SchemaURL, }, }, }, @@ -208,6 +210,51 @@ func TestTrace(t *testing.T) { }, }, }, + { + name: "otelglobal", + event: &probe.Event{ + Kind: trace.SpanKindClient, + SpanEvents: []*probe.SpanEvent{ + { + SpanName: "very important span", + StartTime: startTime.Unix(), + EndTime: endTime.Unix(), + SpanContext: &spanContext, + Attributes: []attribute.KeyValue{ + attribute.Int64("int.value", 42), + attribute.String("string.value", "hello"), + attribute.Float64("float.value", 3.14), + attribute.Bool("bool.value", true), + }, + Status: probe.Status{Code: codes.Error, Description: "error description"}, + TracerName: "user-tracer", + TracerVersion: "v1", + TracerSchema: "user-schema", + }, + }, + }, + expected: tracetest.SpanStubs{ + { + Name: "very important span", + SpanKind: trace.SpanKindClient, + StartTime: convertedStartTime, + EndTime: convertedEndTime, + Resource: instResource(), + InstrumentationLibrary: instrumentation.Library{ + Name: "user-tracer", + Version: "v1", + SchemaURL: "user-schema", + }, + Attributes: []attribute.KeyValue{ + attribute.Int64("int.value", 42), + attribute.String("string.value", "hello"), + attribute.Float64("float.value", 3.14), + attribute.Bool("bool.value", true), + }, + Status: sdktrace.Status{Code: codes.Error, Description: "error description"}, + }, + }, + }, } for _, tt := range testCases { @@ -226,3 +273,35 @@ func TestTrace(t *testing.T) { }) } } + +func TestGetTracer(t *testing.T) { + logger := stdr.New(log.New(os.Stderr, "", log.LstdFlags)) + + exporter := tracetest.NewInMemoryExporter() + tp := sdktrace.NewTracerProvider( + sdktrace.WithSampler(sdktrace.AlwaysSample()), + sdktrace.WithBatcher(exporter), + sdktrace.WithResource(instResource()), + ) + defer func() { + err := tp.Shutdown(context.Background()) + assert.NoError(t, err) + }() + + ctrl, err := NewController(logger, tp, "test") + assert.NoError(t, err) + + t1 := ctrl.getTracer("foo/bar", "test", "v1", "schema") + assert.Equal(t, t1, ctrl.tracersMap[tracerID{name: "test", version: "v1", schema: "schema"}]) + assert.Nil(t, ctrl.tracersMap[tracerID{name: "foo/bar", version: "v1", schema: "schema"}]) + + t2 := ctrl.getTracer("net/http", "", "", "") + assert.Equal(t, t2, ctrl.tracersMap[tracerID{name: "net/http", version: ctrl.version, schema: ""}]) + + t3 := ctrl.getTracer("foo/bar", "test", "v1", "schema") + assert.Same(t, t1, t3) + + t4 := ctrl.getTracer("net/http", "", "", "") + assert.Same(t, t2, t4) + assert.Equal(t, len(ctrl.tracersMap), 2) +} diff --git a/internal/test/e2e/databasesql/traces.json b/internal/test/e2e/databasesql/traces.json index 36168b9d2..2c81f0304 100644 --- a/internal/test/e2e/databasesql/traces.json +++ b/internal/test/e2e/databasesql/traces.json @@ -50,6 +50,7 @@ "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scopeSpans": [ { + "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scope": { "name": "go.opentelemetry.io/auto/database/sql", "version": "v0.13.0-alpha" @@ -75,6 +76,7 @@ ] }, { + "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scope": { "name": "go.opentelemetry.io/auto/net/http", "version": "v0.13.0-alpha" diff --git a/internal/test/e2e/gin/traces.json b/internal/test/e2e/gin/traces.json index 78a7834c8..b83a347b0 100644 --- a/internal/test/e2e/gin/traces.json +++ b/internal/test/e2e/gin/traces.json @@ -50,6 +50,7 @@ "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scopeSpans": [ { + "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scope": { "name": "go.opentelemetry.io/auto/net/http", "version": "v0.13.0-alpha" diff --git a/internal/test/e2e/grpc/traces.json b/internal/test/e2e/grpc/traces.json index 3c50fd4d1..f5d5a595a 100644 --- a/internal/test/e2e/grpc/traces.json +++ b/internal/test/e2e/grpc/traces.json @@ -50,6 +50,7 @@ "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scopeSpans": [ { + "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scope": { "name": "go.opentelemetry.io/auto/google.golang.org/grpc", "version": "v0.13.0-alpha" diff --git a/internal/test/e2e/kafka-go/traces.json b/internal/test/e2e/kafka-go/traces.json index 5b7253f9a..ce52aff20 100644 --- a/internal/test/e2e/kafka-go/traces.json +++ b/internal/test/e2e/kafka-go/traces.json @@ -50,6 +50,7 @@ "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scopeSpans": [ { + "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scope": { "name": "go.opentelemetry.io/auto/github.com/segmentio/kafka-go", "version": "v0.13.0-alpha" @@ -191,6 +192,7 @@ "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scopeSpans": [ { + "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scope": { "name": "go.opentelemetry.io/auto/github.com/segmentio/kafka-go", "version": "v0.13.0-alpha" diff --git a/internal/test/e2e/nethttp/traces.json b/internal/test/e2e/nethttp/traces.json index 4ecb71016..1f1908939 100644 --- a/internal/test/e2e/nethttp/traces.json +++ b/internal/test/e2e/nethttp/traces.json @@ -50,6 +50,7 @@ "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scopeSpans": [ { + "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scope": { "name": "go.opentelemetry.io/auto/net/http", "version": "v0.13.0-alpha" diff --git a/internal/test/e2e/nethttp_custom/traces.json b/internal/test/e2e/nethttp_custom/traces.json index 2d20834c4..58c2b2ac6 100644 --- a/internal/test/e2e/nethttp_custom/traces.json +++ b/internal/test/e2e/nethttp_custom/traces.json @@ -50,6 +50,7 @@ "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scopeSpans": [ { + "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scope": { "name": "go.opentelemetry.io/auto/net/http", "version": "v0.13.0-alpha" diff --git a/internal/test/e2e/otelglobal/go.mod b/internal/test/e2e/otelglobal/go.mod index 45f5bb2ca..28f44fd27 100644 --- a/internal/test/e2e/otelglobal/go.mod +++ b/internal/test/e2e/otelglobal/go.mod @@ -2,11 +2,13 @@ module go.opentelemetry.io/auto/internal/test/e2e/otelglobal go 1.22.0 -require go.opentelemetry.io/otel v1.28.0 +require ( + go.opentelemetry.io/otel v1.28.0 + go.opentelemetry.io/otel/trace v1.28.0 +) require ( github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect ) diff --git a/internal/test/e2e/otelglobal/main.go b/internal/test/e2e/otelglobal/main.go index d232e2bee..58e79af7f 100644 --- a/internal/test/e2e/otelglobal/main.go +++ b/internal/test/e2e/otelglobal/main.go @@ -10,9 +10,14 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" ) -var tracer = otel.Tracer("trace-example") +var tracer = otel.Tracer( + "trace-example", + trace.WithInstrumentationVersion("v1.23.42"), + trace.WithSchemaURL("https://some_schema"), +) func innerFunction(ctx context.Context) { _, span := tracer.Start(ctx, "child") diff --git a/internal/test/e2e/otelglobal/traces.json b/internal/test/e2e/otelglobal/traces.json index 2be97f792..89f272c08 100644 --- a/internal/test/e2e/otelglobal/traces.json +++ b/internal/test/e2e/otelglobal/traces.json @@ -50,9 +50,10 @@ "schemaUrl": "https://opentelemetry.io/schemas/1.26.0", "scopeSpans": [ { + "schemaUrl": "https://some_schema", "scope": { - "name": "go.opentelemetry.io/auto/go.opentelemetry.io/otel/internal/global", - "version": "v0.13.0-alpha" + "name": "trace-example", + "version": "v1.23.42" }, "spans": [ { diff --git a/internal/test/e2e/otelglobal/verify.bats b/internal/test/e2e/otelglobal/verify.bats index 5a4b37a30..54332ed8f 100644 --- a/internal/test/e2e/otelglobal/verify.bats +++ b/internal/test/e2e/otelglobal/verify.bats @@ -2,13 +2,23 @@ load ../../test_helpers/utilities -SCOPE="go.opentelemetry.io/auto/go.opentelemetry.io/otel/internal/global" +SCOPE="trace-example" @test "go-auto :: includes service.name in resource attributes" { result=$(resource_attributes_received | jq "select(.key == \"service.name\").value.stringValue") assert_equal "$result" '"sample-app"' } +@test "go-auto :: include tracer version in scope" { + result=$(spans_received | jq ".scopeSpans[].scope.version") + assert_equal "$result" '"v1.23.42"' +} + +@test "go-auto :: include schema url" { + result=$(spans_received | jq ".scopeSpans[].schemaUrl") + assert_equal "$result" '"https://some_schema"' +} + @test "server :: valid int attribute" { result=$(span_attributes_for ${SCOPE} | jq "select(.key == \"int_key\").value.intValue") assert_equal "$result" '"42"' diff --git a/internal/tools/inspect/cmd/offsetgen/main.go b/internal/tools/inspect/cmd/offsetgen/main.go index 35567709b..9c641994d 100644 --- a/internal/tools/inspect/cmd/offsetgen/main.go +++ b/internal/tools/inspect/cmd/offsetgen/main.go @@ -161,6 +161,9 @@ func manifests() ([]inspect.Manifest, error) { }, StructFields: []structfield.ID{ structfield.NewID("go.opentelemetry.io/otel", "go.opentelemetry.io/otel/internal/global", "tracer", "delegate"), + structfield.NewID("go.opentelemetry.io/otel", "go.opentelemetry.io/otel/internal/global", "tracer", "name"), + structfield.NewID("go.opentelemetry.io/otel", "go.opentelemetry.io/otel/internal/global", "tracer", "provider"), + structfield.NewID("go.opentelemetry.io/otel", "go.opentelemetry.io/otel/internal/global", "tracerProvider", "tracers"), }, }, {