diff --git a/ddtrace/tracer/otelprocesscontext.go b/ddtrace/tracer/otelprocesscontext.go new file mode 100644 index 0000000000..f690ec905d --- /dev/null +++ b/ddtrace/tracer/otelprocesscontext.go @@ -0,0 +1,27 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2025 Datadog, Inc. +package tracer + +// OtelProcessContext represents the OTEL context for the process. +// +//go:generate go run github.com/tinylib/msgp -unexported -marshal=true -o=otelprocesscontext_msgp.go -tests=false +type otelProcessContext struct { + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/deployment/#deployment-environment-name + DeploymentEnvironmentName string `msg:"deployment.environment.name"` + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/host/#host-name + HostName string `msg:"host.name"` + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/service/#service-instance-id + ServiceInstanceID string `msg:"service.instance.id"` + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/service/#service-name + ServiceName string `msg:"service.name"` + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/service/#service-version + ServiceVersion string `msg:"service.version"` + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/telemetry/#telemetry-sdk-language + TelemetrySDKLanguage string `msg:"telemetry.sdk.language"` + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/telemetry/#telemetry-sdk-version + TelemetrySDKVersion string `msg:"telemetry.sdk.version"` + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/telemetry/#telemetry-sdk-name + TelemetrySdkName string `msg:"telemetry.sdk.name"` +} diff --git a/ddtrace/tracer/otelprocesscontext_msgp.go b/ddtrace/tracer/otelprocesscontext_msgp.go new file mode 100644 index 0000000000..5b568286c5 --- /dev/null +++ b/ddtrace/tracer/otelprocesscontext_msgp.go @@ -0,0 +1,285 @@ +// Code generated by github.com/tinylib/msgp DO NOT EDIT. + +package tracer + +import ( + "github.com/tinylib/msgp/msgp" +) + +// DecodeMsg implements msgp.Decodable +func (z *otelProcessContext) DecodeMsg(dc *msgp.Reader) (err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, err = dc.ReadMapKeyPtr() + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "deployment.environment.name": + z.DeploymentEnvironmentName, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "DeploymentEnvironmentName") + return + } + case "host.name": + z.HostName, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "HostName") + return + } + case "service.instance.id": + z.ServiceInstanceID, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "ServiceInstanceID") + return + } + case "service.name": + z.ServiceName, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "ServiceName") + return + } + case "service.version": + z.ServiceVersion, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "ServiceVersion") + return + } + case "telemetry.sdk.language": + z.TelemetrySDKLanguage, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "TelemetrySDKLanguage") + return + } + case "telemetry.sdk.version": + z.TelemetrySDKVersion, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "TelemetrySDKVersion") + return + } + case "telemetry.sdk.name": + z.TelemetrySdkName, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "TelemetrySdkName") + return + } + default: + err = dc.Skip() + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z *otelProcessContext) EncodeMsg(en *msgp.Writer) (err error) { + // map header, size 8 + // write "deployment.environment.name" + err = en.Append(0x88, 0xbb, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x6e, 0x61, 0x6d, 0x65) + if err != nil { + return + } + err = en.WriteString(z.DeploymentEnvironmentName) + if err != nil { + err = msgp.WrapError(err, "DeploymentEnvironmentName") + return + } + // write "host.name" + err = en.Append(0xa9, 0x68, 0x6f, 0x73, 0x74, 0x2e, 0x6e, 0x61, 0x6d, 0x65) + if err != nil { + return + } + err = en.WriteString(z.HostName) + if err != nil { + err = msgp.WrapError(err, "HostName") + return + } + // write "service.instance.id" + err = en.Append(0xb3, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x69, 0x64) + if err != nil { + return + } + err = en.WriteString(z.ServiceInstanceID) + if err != nil { + err = msgp.WrapError(err, "ServiceInstanceID") + return + } + // write "service.name" + err = en.Append(0xac, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x6e, 0x61, 0x6d, 0x65) + if err != nil { + return + } + err = en.WriteString(z.ServiceName) + if err != nil { + err = msgp.WrapError(err, "ServiceName") + return + } + // write "service.version" + err = en.Append(0xaf, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e) + if err != nil { + return + } + err = en.WriteString(z.ServiceVersion) + if err != nil { + err = msgp.WrapError(err, "ServiceVersion") + return + } + // write "telemetry.sdk.language" + err = en.Append(0xb6, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65) + if err != nil { + return + } + err = en.WriteString(z.TelemetrySDKLanguage) + if err != nil { + err = msgp.WrapError(err, "TelemetrySDKLanguage") + return + } + // write "telemetry.sdk.version" + err = en.Append(0xb5, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e) + if err != nil { + return + } + err = en.WriteString(z.TelemetrySDKVersion) + if err != nil { + err = msgp.WrapError(err, "TelemetrySDKVersion") + return + } + // write "telemetry.sdk.name" + err = en.Append(0xb2, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x6e, 0x61, 0x6d, 0x65) + if err != nil { + return + } + err = en.WriteString(z.TelemetrySdkName) + if err != nil { + err = msgp.WrapError(err, "TelemetrySdkName") + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z *otelProcessContext) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // map header, size 8 + // string "deployment.environment.name" + o = append(o, 0x88, 0xbb, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x6e, 0x61, 0x6d, 0x65) + o = msgp.AppendString(o, z.DeploymentEnvironmentName) + // string "host.name" + o = append(o, 0xa9, 0x68, 0x6f, 0x73, 0x74, 0x2e, 0x6e, 0x61, 0x6d, 0x65) + o = msgp.AppendString(o, z.HostName) + // string "service.instance.id" + o = append(o, 0xb3, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x69, 0x64) + o = msgp.AppendString(o, z.ServiceInstanceID) + // string "service.name" + o = append(o, 0xac, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x6e, 0x61, 0x6d, 0x65) + o = msgp.AppendString(o, z.ServiceName) + // string "service.version" + o = append(o, 0xaf, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e) + o = msgp.AppendString(o, z.ServiceVersion) + // string "telemetry.sdk.language" + o = append(o, 0xb6, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65) + o = msgp.AppendString(o, z.TelemetrySDKLanguage) + // string "telemetry.sdk.version" + o = append(o, 0xb5, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e) + o = msgp.AppendString(o, z.TelemetrySDKVersion) + // string "telemetry.sdk.name" + o = append(o, 0xb2, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x6e, 0x61, 0x6d, 0x65) + o = msgp.AppendString(o, z.TelemetrySdkName) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *otelProcessContext) UnmarshalMsg(bts []byte) (o []byte, err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, bts, err = msgp.ReadMapKeyZC(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "deployment.environment.name": + z.DeploymentEnvironmentName, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "DeploymentEnvironmentName") + return + } + case "host.name": + z.HostName, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "HostName") + return + } + case "service.instance.id": + z.ServiceInstanceID, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "ServiceInstanceID") + return + } + case "service.name": + z.ServiceName, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "ServiceName") + return + } + case "service.version": + z.ServiceVersion, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "ServiceVersion") + return + } + case "telemetry.sdk.language": + z.TelemetrySDKLanguage, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "TelemetrySDKLanguage") + return + } + case "telemetry.sdk.version": + z.TelemetrySDKVersion, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "TelemetrySDKVersion") + return + } + case "telemetry.sdk.name": + z.TelemetrySdkName, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "TelemetrySdkName") + return + } + default: + bts, err = msgp.Skip(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z *otelProcessContext) Msgsize() (s int) { + s = 1 + 28 + msgp.StringPrefixSize + len(z.DeploymentEnvironmentName) + 10 + msgp.StringPrefixSize + len(z.HostName) + 20 + msgp.StringPrefixSize + len(z.ServiceInstanceID) + 13 + msgp.StringPrefixSize + len(z.ServiceName) + 16 + msgp.StringPrefixSize + len(z.ServiceVersion) + 23 + msgp.StringPrefixSize + len(z.TelemetrySDKLanguage) + 22 + msgp.StringPrefixSize + len(z.TelemetrySDKVersion) + 19 + msgp.StringPrefixSize + len(z.TelemetrySdkName) + return +} diff --git a/ddtrace/tracer/tracer.go b/ddtrace/tracer/tracer.go index dd06d845ab..c7ce3870e9 100644 --- a/ddtrace/tracer/tracer.go +++ b/ddtrace/tracer/tracer.go @@ -277,15 +277,20 @@ func Start(opts ...StartOption) error { // DD_INSTRUMENTATION_TELEMETRY_ENABLED env var t.telemetry = startTelemetry(t.config) - // store the configuration in an in-memory file, allowing it to be read to - // determine if the process is instrumented with a tracer and to retrive - // relevant tracing information. + // store the configuration in an in-memory file and in a named anonymous mapping, + // allowing it to be read to determine if the process is instrumented with a tracer + // and to retrieve relevant tracing information. storeConfig(t.config) globalinternal.SetTracerInitialized(true) return nil } +// storeConfig stores the process level tracing context both in an in-memory file and +// in a named anonymous mapping. +// This allows an external process, such as the Datadog Agent or fullhost profiler, +// to determine if the process is instrumented with a tracer and to retrieve the process +// level tracing context. func storeConfig(c *config) { uuid, _ := uuid.NewRandom() name := fmt.Sprintf("datadog-tracer-info-%s", uuid.String()[0:8]) @@ -308,6 +313,23 @@ func storeConfig(c *config) { if err != nil { log.Error("failed to store the configuration: %s", err.Error()) } + + processContext := otelProcessContext{ + DeploymentEnvironmentName: c.env, + HostName: c.hostname, + ServiceInstanceID: globalconfig.RuntimeID(), + ServiceName: c.serviceName, + ServiceVersion: c.version, + TelemetrySDKLanguage: "go", + TelemetrySDKVersion: version.Tag, + TelemetrySdkName: "dd-trace-go", + } + + data, _ = processContext.MarshalMsg(nil) + err = globalinternal.CreateOtelProcessContextMapping(data) + if err != nil { + log.Error("failed to store the OTEL process context: %s", err.Error()) + } } // Stop stops the started tracer. Subsequent calls are valid but become no-op. diff --git a/internal/otelcontextmapping.go b/internal/otelcontextmapping.go new file mode 100644 index 0000000000..6fc8e5bf21 --- /dev/null +++ b/internal/otelcontextmapping.go @@ -0,0 +1,12 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2025 Datadog, Inc. + +//go:build !linux + +package internal + +func CreateOtelProcessContextMapping(data []byte) error { + return nil +} diff --git a/internal/otelcontextmapping_linux.go b/internal/otelcontextmapping_linux.go new file mode 100644 index 0000000000..e5fa4cd6c9 --- /dev/null +++ b/internal/otelcontextmapping_linux.go @@ -0,0 +1,130 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2025 Datadog, Inc. + +//go:build linux + +// This is a go port of https://github.com/DataDog/fullhost-code-hotspots-wip/blob/main/lang-exp/anonmapping-clib/otel_process_ctx.c + +package internal + +import ( + "fmt" + "os" + "structs" + "sync" + "unsafe" + + "golang.org/x/sys/unix" +) + +const ( + // These two constants are not in x/sys/unix by default; copy them from . + //nolint:revive + PR_SET_VMA = 0x53564D41 + //nolint:revive + PR_SET_VMA_ANON_NAME = 0 + + otelContextSignature = "OTEL_CTX" +) + +var ( + otelContextMappingSize = 2 * os.Getpagesize() + + existingMappingBytes []byte + publisherPID int +) + +type processContextHeader struct { + _ structs.HostLayout + Signature [8]byte + Version uint32 + PayloadSize uint32 + PayloadAddr uintptr +} + +func CreateOtelProcessContextMapping(data []byte) error { + // Clear the previous mapping if it exists + err := removeOtelProcessContextMapping() + if err != nil { + return fmt.Errorf("failed to remove previous mapping: %w", err) + } + + headerSize := int(unsafe.Sizeof(processContextHeader{})) + if len(data)+headerSize > otelContextMappingSize { + return fmt.Errorf("data size is too large for the mapping size") + } + + mappingBytes, err := unix.Mmap( + -1, // fd = -1 for an anonymous mapping + 0, // offset + otelContextMappingSize, // length + unix.PROT_READ|unix.PROT_WRITE, + unix.MAP_PRIVATE|unix.MAP_ANONYMOUS, + ) + if err != nil { + return fmt.Errorf("failed to mmap: %w", err) + } + + err = unix.Madvise(mappingBytes, unix.MADV_DONTFORK) + if err != nil { + _ = unix.Munmap(mappingBytes) + return fmt.Errorf("failed to madvise: %w", err) + } + + addr := uintptr(unsafe.Pointer(&mappingBytes[0])) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + header := processContextHeader{ + Version: 1, + PayloadSize: uint32(len(data)), + PayloadAddr: addr + uintptr(headerSize), + } + copy(mappingBytes[headerSize:], data) + copy(mappingBytes[:headerSize], unsafe.Slice((*byte)(unsafe.Pointer(&header)), headerSize)) + }() + wg.Wait() + // write the signature last to ensure that once a process validates the signature, it can safely read the whole data + copy(mappingBytes, otelContextSignature) + + err = unix.Mprotect(mappingBytes, unix.PROT_READ) + if err != nil { + _ = unix.Munmap(mappingBytes) + return fmt.Errorf("failed to mprotect: %w", err) + } + + // prctl expects a null-terminated string + contextNameNullTerminated, _ := unix.ByteSliceFromString(otelContextSignature) + // Failure to set the vma anon name is not a critical error (only supported on Linux 5.17+), so we ignore the return value. + _ = unix.Prctl( + PR_SET_VMA, + uintptr(PR_SET_VMA_ANON_NAME), + addr, + uintptr(otelContextMappingSize), + uintptr(unsafe.Pointer(&contextNameNullTerminated[0])), + ) + + existingMappingBytes = mappingBytes + publisherPID = os.Getpid() + return nil +} + +func removeOtelProcessContextMapping() error { + //Check publisher PID to check that the process has not forked. + //It should not be necessary for Go, but just in case. + if existingMappingBytes == nil || publisherPID != os.Getpid() { + return nil + } + + err := unix.Munmap(existingMappingBytes) + if err != nil { + return fmt.Errorf("failed to munmap: %w", err) + } + existingMappingBytes = nil + publisherPID = 0 + return nil +} diff --git a/internal/otelcontextmapping_linux_test.go b/internal/otelcontextmapping_linux_test.go new file mode 100644 index 0000000000..ac0bbbfab3 --- /dev/null +++ b/internal/otelcontextmapping_linux_test.go @@ -0,0 +1,144 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2025 Datadog, Inc. + +//go:build linux + +package internal + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "os" + "strconv" + "strings" + "testing" + "unsafe" + + "github.com/stretchr/testify/require" + "golang.org/x/sys/unix" +) + +func getContextFromMapping(fields []string) []byte { + if fields[1] != "r--p" || fields[4] != "0" || fields[3] != "00:00" { + return nil + } + + addrs := strings.SplitN(fields[0], "-", 2) + if len(addrs) < 2 { + return nil + } + vaddr, err := strconv.ParseUint(addrs[0], 16, 64) + if err != nil { + return nil + } + + vend, err := strconv.ParseUint(addrs[1], 16, 64) + if err != nil { + return nil + } + + length := vend - vaddr + if length != uint64(otelContextMappingSize) { + return nil + } + + header := (*processContextHeader)(unsafe.Pointer(uintptr(vaddr))) + if string(header.Signature[:]) != otelContextSignature { + return nil + } + if header.Version != 1 { + return nil + } + + payload := make([]byte, header.PayloadSize) + copy(payload, unsafe.Slice((*byte)(unsafe.Pointer(header.PayloadAddr)), header.PayloadSize)) + return payload +} + +func getContextMapping(mapsFile io.Reader, useMappingNames bool) ([]byte, error) { + minFields := 5 + if useMappingNames { + minFields++ + } + scanner := bufio.NewScanner(mapsFile) + for scanner.Scan() { + + line := scanner.Text() + fields := strings.Fields(line) + if len(fields) < minFields { + continue + } + + if (useMappingNames && fields[5] != "[anon:OTEL_CTX]") || (!useMappingNames && fields[5] != "") { + continue + } + + payload := getContextFromMapping(fields) + if payload != nil { + return payload, nil + } + + if useMappingNames { + // When using mapping names, we can stop after the first match. + break + } + } + return nil, errors.New("no context mapping found") +} + +func readProcessLevelContext(useMappingNames bool) ([]byte, error) { + mapsFile, err := os.Open("/proc/self/maps") + if err != nil { + return nil, err + } + defer mapsFile.Close() + + return getContextMapping(mapsFile, useMappingNames) +} + +func kernelSupportsNamedAnonymousMappings() (bool, error) { + var uname unix.Utsname + if err := unix.Uname(&uname); err != nil { + return false, fmt.Errorf("could not get Kernel Version: %v", err) + } + var major, minor, patch uint32 + _, _ = fmt.Fscanf(bytes.NewReader(uname.Release[:]), "%d.%d.%d", &major, &minor, &patch) + + return major > 5 || (major == 5 && minor >= 17), nil +} + +func TestCreateOtelProcessContextMapping(t *testing.T) { + removeOtelProcessContextMapping() + t.Cleanup(func() { + removeOtelProcessContextMapping() + }) + + payload := []byte("hello world") + err := CreateOtelProcessContextMapping(payload) + require.NoError(t, err) + + supportsNamedAnonymousMappings, err := kernelSupportsNamedAnonymousMappings() + require.NoError(t, err) + + ctx, err := readProcessLevelContext(supportsNamedAnonymousMappings) + require.NoError(t, err) + require.Equal(t, payload, ctx) +} + +func TestCreateOtelProcessContextMappingRejectsOversizedPayload(t *testing.T) { + removeOtelProcessContextMapping() + t.Cleanup(func() { + removeOtelProcessContextMapping() + }) + + headerSize := int(unsafe.Sizeof(processContextHeader{})) + oversizedPayload := make([]byte, otelContextMappingSize-headerSize+1) + + err := CreateOtelProcessContextMapping(oversizedPayload) + require.Error(t, err) +}