{"owner":"open-telemetry","repo":"opentelemetry-go","hasSkills":true,"totalSkillsCount":3,"totalTokensCount":7186,"categories":["project-spec","root-instruction","copilot-instructions"],"hasMcp":false,"mcpConfig":null,"found":["log/DESIGN.md","AGENTS.md",".github/copilot-instructions.md"],"skills":{"log/DESIGN.md":"# Logs API\n\n## Abstract\n\n`go.opentelemetry.io/otel/log` provides\n[Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/).\n\nThe prototype was created in\n[#4725](https://github.com/open-telemetry/opentelemetry-go/pull/4725).\n\n## Background\n\nThe key challenge is to create a performant API compliant with the [specification](https://opentelemetry.io/docs/specs/otel/logs/api/)\nwith an intuitive and user friendly design.\nPerformance is seen as one of the most important characteristics of logging libraries in Go.\n\n## Design\n\nThis proposed design aims to:\n\n- be specification compliant,\n- be similar to Trace and Metrics API,\n- take advantage of both OpenTelemetry and `slog` experience to achieve acceptable performance.\n\n### Module structure\n\nThe API is published as a single `go.opentelemetry.io/otel/log` Go module.\n\nThe package structure is similar to Trace API and Metrics API.\nThe Go module consists of the following packages:\n\n- `go.opentelemetry.io/otel/log`\n- `go.opentelemetry.io/otel/log/embedded`\n- `go.opentelemetry.io/otel/log/logtest`\n- `go.opentelemetry.io/otel/log/noop`\n\nRejected alternative:\n\n- [Reuse slog](#reuse-slog)\n\n### LoggerProvider\n\nThe [`LoggerProvider` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#loggerprovider)\nis defined as `LoggerProvider` interface in [provider.go](provider.go).\n\nThe specification may add new operations to `LoggerProvider`.\nThe interface may have methods added without a package major version bump.\nThis embeds `embedded.LoggerProvider` to help inform an API implementation\nauthor about this non-standard API evolution.\nThis approach is already used in Trace API and Metrics API.\n\n#### LoggerProvider.Logger\n\nThe `Logger` method implements the [`Get a Logger` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#get-a-logger).\n\nThe required `name` parameter is accepted as a `string` method argument.\n\nThe `LoggerOption` options are defined to support optional parameters.\n\nImplementation requirements:\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements)\n  the method to be safe to be called concurrently.\n\n- If the passed name is empty, this should be reported as invalid as specified\n  by the [Logs SDK specification](https://opentelemetry.io/docs/specs/otel/logs/sdk/#logger-creation).\n  The method should still use it as the instrumentation scope name and return\n  a working logger.\n\n`Logger` can be extended by adding new `LoggerOption` options\nand adding new exported fields to the `LoggerConfig` struct.\nThis design is already used in Trace API for getting tracers\nand in Metrics API for getting meters.\n\nRejected alternative:\n\n- [Passing struct as parameter to LoggerProvider.Logger](#passing-struct-as-parameter-to-loggerproviderlogger).\n\n### Logger\n\nThe [`Logger` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#logger)\nis defined as `Logger` interface in [logger.go](logger.go).\n\nThe specification may add new operations to `Logger`.\nThe interface may have methods added without a package major version bump.\nThis embeds `embedded.Logger` to help inform an API implementation\nauthor about this non-standard API evolution.\nThis approach is already used in Trace API and Metrics API.\n\n### Logger.Emit\n\nThe `Emit` method implements the [`Emit a LogRecord` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord).\n\n[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)\nis accepted as a `context.Context` method argument.\n\nCalls to `Emit` are supposed to be on the hot path.\nTherefore, in order to reduce the number of heap allocations,\nthe [`LogRecord` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord),\nis defined as `Record` struct  in [record.go](record.go).\n\n[`Timestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-timestamp)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Timestamp() time.Time\nfunc (r *Record) SetTimestamp(t time.Time)\n```\n\n[`ObservedTimestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-observedtimestamp)\nis accessed using following methods:\n\n```go\nfunc (r *Record) ObservedTimestamp() time.Time\nfunc (r *Record) SetObservedTimestamp(t time.Time)\n```\n\n[`EventName`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-eventname)\nis accessed using following methods:\n\n```go\nfunc (r *Record) EventName() string\nfunc (r *Record) SetEventName(s string)\n```\n\n[`SeverityNumber`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Severity() Severity\nfunc (r *Record) SetSeverity(s Severity)\n```\n\n`Severity` type is defined in [severity.go](severity.go).\nThe constants are are based on\n[Displaying Severity recommendation](https://opentelemetry.io/docs/specs/otel/logs/data-model/#displaying-severity).\nAdditionally, `Severity[Level]` constants are defined to make the API more readable and user friendly.\n\n[`SeverityText`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext)\nis accessed using following methods:\n\n```go\nfunc (r *Record) SeverityText() string\nfunc (r *Record) SetSeverityText(s string)\n```\n\n[`Body`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Body() attribute.Value\nfunc (r *Record) SetBody(v attribute.Value)\n```\n\n[Log record attributes](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-attributes)\nare accessed using following methods:\n\n```go\nfunc (r *Record) WalkAttributes(f func(attribute.KeyValue) bool)\nfunc (r *Record) AddAttributes(attrs ...attribute.KeyValue)\n```\n\n`Record` has a `AttributesLen` method that returns\nthe number of attributes to allow slice preallocation\nwhen converting records to a different representation:\n\n```go\nfunc (r *Record) AttributesLen() int\n```\n\nThe records attributes design and implementation is based on\n[`slog.Record`](https://pkg.go.dev/log/slog#Record).\nIt allows achieving high-performance access and manipulation of the attributes\nwhile keeping the API user friendly.\nIt relieves the user from making his own improvements\nfor reducing the number of allocations when passing attributes.\n\nLog body and attributes use the common\n[`attribute.Value`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#Value)\nand\n[`attribute.KeyValue`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#KeyValue)\ntypes.\nThese types cover the Logs Data Model `any` value shape, including empty\nvalues, byte slices, generic slices, and maps.\nReusing the attribute package keeps the API consistent across signals and\navoids maintaining a second value model with conversion helpers.\n\nThe zero value of `attribute.Value` represents an empty body.\nLog maps use `attribute.MAP`, which may contain duplicate keys when callers\nconstruct one that way. Duplicate-key normalization is an SDK policy, not an\nAPI behavior.\n\nThe caller must not subsequently mutate the record passed to `Emit`.\nThis would allow the implementation to not clone the record,\nbut simply retain, modify or discard it.\nThe implementation may still choose to clone the record or copy its attributes\nif it needs to retain or modify it,\ne.g. in case of asynchronous processing to eliminate the possibility of data races,\nbecause the user can technically reuse the record and add new attributes\nafter the call (even when the documentation says that the caller must not do it).\n\nImplementation requirements:\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements)\n  the method to be safe to be called concurrently.\n\n- The method must not interrupt the record processing if the context is canceled\n  per [\"ignoring context cancellation\" guideline](../CONTRIBUTING.md#ignoring-context-cancellation).\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord)\n  use the current time as observed timestamp if the passed is empty.\n\n- The method should handle the trace context passed via `ctx` argument in order to meet the\n  [specification's SDK requirement](https://opentelemetry.io/docs/specs/otel/logs/sdk/#readablelogrecord)\n  to populate the trace context fields from the resolved context.\n\n`Emit` can be extended by adding new exported fields to the `Record` struct.\n\nRejected alternatives:\n\n- [Record as interface](#record-as-interface)\n- [Options as parameter to Logger.Emit](#options-as-parameter-to-loggeremit)\n- [Passing record as pointer to Logger.Emit](#passing-record-as-pointer-to-loggeremit)\n- [Logger.WithAttributes](#loggerwithattributes)\n- [Record attributes as slice](#record-attributes-as-slice)\n- [Use any instead of attribute.Value](#use-any-instead-of-attributevalue)\n- [Severity type encapsulating number and text](#severity-type-encapsulating-number-and-text)\n- [Define log-specific value types](#define-log-specific-value-types)\n- [Mix receiver types for Record](#mix-receiver-types-for-record)\n- [Add XYZ method to Logger](#add-xyz-method-to-logger)\n\n### Logger.Enabled\n\nThe `Enabled` method implements the [`Enabled` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#enabled).\n\n[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)\nis accepted as a `context.Context` method argument.\n\nCalls to `Enabled` are supposed to be on the hot path and the list of arguments\ncan be extendend in future. Therefore, in order to reduce the number of heap\nallocations and make it possible to handle new arguments, `Enabled` accepts\na `EnabledParameters` struct, defined in [logger.go](logger.go), as the second\nmethod argument.\n\nThe `EnabledParameters` uses fields, instead of getters and setters, to allow\nsimpler usage which allows configuring the `EnabledParameters` in the same line\nwhere `Enabled` is called.\n\n### noop package\n\nThe `go.opentelemetry.io/otel/log/noop` package provides\n[Logs API No-Op Implementation](https://opentelemetry.io/docs/specs/otel/logs/noop/).\n\n### Trace context correlation\n\nThe bridge implementation should do its best to pass\nthe `ctx` containing the trace context from the caller\nso it can later be passed via `Logger.Emit`.\n\nIt is not expected that users (caller or bridge implementation) reconstruct\na `context.Context`. Reconstructing a `context.Context` with\n[`trace.ContextWithSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#ContextWithSpanContext)\nand [`trace.NewSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#NewSpanContext)\nwould usually involve more memory allocations.\n\nThe logging libraries which have recording methods that accepts `context.Context`,\nsuch us [`slog`](https://pkg.go.dev/log/slog),\n[`logrus`](https://pkg.go.dev/github.com/sirupsen/logrus),\n[`zerolog`](https://pkg.go.dev/github.com/rs/zerolog),\nmakes passing the trace context trivial.\n\nHowever, some libraries do not accept a `context.Context` in their recording methods.\nStructured logging libraries,\nsuch as [`logr`](https://pkg.go.dev/github.com/go-logr/logr)\nand [`zap`](https://pkg.go.dev/go.uber.org/zap),\noffer passing `any` type as a log attribute/field.\nTherefore, their bridge implementations can define a \"special\" log attributes/field\nthat will be used to capture the trace context.\n\n[The prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725)\nhas bridge implementations that handle trace context correlation efficiently.\n\n## Benchmarking\n\nThe benchmarks take inspiration from [`slog`](https://pkg.go.dev/log/slog),\nbecause for the Go team it was also critical to create API that would be fast\nand interoperable with existing logging packages.[^2][^3]\n\nThe benchmark results can be found in [the prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725).\n\n## Rejected alternatives\n\n### Reuse slog\n\nThe API must not be coupled to [`slog`](https://pkg.go.dev/log/slog),\nnor any other logging library.\n\nThe API needs to evolve orthogonally to `slog`.\n\n`slog` is not compliant with the [Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/).\nand we cannot expect the Go team to make `slog` compliant with it.\n\nThe interoperability can be achieved using [a log bridge](https://opentelemetry.io/docs/specs/otel/glossary/#log-appender--bridge).\n\nYou can read more about OpenTelemetry Logs design on [opentelemetry.io](https://opentelemetry.io/docs/concepts/signals/logs/).\n\n### Record as interface\n\n`Record` is defined as a `struct` because of the following reasons.\n\nLog record is a value object without any behavior.\nIt is used as data input for Logger methods.\n\nThe log record resembles the instrument config structs like [metric.Float64CounterConfig](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Float64CounterConfig).\n\nUsing `struct` instead of `interface` improves the performance as e.g.\nindirect calls are less optimized,\nusage of interfaces tend to increase heap allocations.[^3]\n\n### Options as parameter to Logger.Emit\n\nOne of the initial ideas was to have:\n\n```go\ntype Logger interface{\n\tembedded.Logger\n\tEmit(ctx context.Context, options ...RecordOption)\n}\n```\n\nThe main reason was that design would be similar\nto the [Meter API](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Meter)\nfor creating instruments.\n\nHowever, passing `Record` directly, instead of using options,\nis more performant as it reduces heap allocations.[^4]\n\nAnother advantage of passing `Record` is that API would not have functions like `NewRecord(options...)`,\nwhich would be used by the SDK and not by the users.\n\nFinally, the definition would be similar to [`slog.Handler.Handle`](https://pkg.go.dev/log/slog#Handler)\nthat was designed to provide optimization opportunities.[^2]\n\n### Passing record as pointer to Logger.Emit\n\nSo far the benchmarks do not show differences that would\nfavor passing the record via pointer (and vice versa).\n\nPassing via value feels safer because of the following reasons.\n\nThe user would not be able to pass `nil`.\nTherefore, it reduces the possibility to have a nil pointer dereference.\n\nIt should reduce the possibility of a heap allocation.\n\nIt follows the design of [`slog.Handler`](https://pkg.go.dev/log/slog#Handler).\n\nIf follows one of Google's Go Style Decisions\nto prefer [passing values](https://google.github.io/styleguide/go/decisions#pass-values).\n\n### Passing struct as parameter to LoggerProvider.Logger\n\nSimilarly to `Logger.Emit`, we could have something like:\n\n```go\ntype LoggerProvider interface{\n\tembedded.LoggerProvider\n\tLogger(name string, config LoggerConfig)\n}\n```\n\nThe drawback of this idea would be that this would be\na different design from Trace and Metrics API.\n\nThe performance of acquiring a logger is not as critical\nas the performance of emitting a log record. While a single\nHTTP/RPC handler could write hundreds of logs, it should not\ncreate a new logger for each log entry.\nThe bridge implementation should reuse loggers whenever possible.\n\n### Logger.WithAttributes\n\nWe could add `WithAttributes` to the `Logger` interface.\nThen `Record` could be a simple struct with only exported fields.\nThe idea was that the SDK would implement the performance improvements\ninstead of doing it in the API.\nThis would allow having different optimization strategies.\n\nDuring the analysis[^5], it occurred that the main problem of this proposal\nis that the variadic slice passed to an interface method is always heap allocated.\n\nMoreover, the logger returned by `WithAttribute` was allocated on the heap.\n\nLastly, the proposal was not specification compliant.\n\n### Record attributes as slice\n\nOne of the proposals[^6] was to have `Record` as a simple struct:\n\n```go\ntype Record struct {\n\tTimestamp         time.Time\n\tObservedTimestamp time.Time\n\tEventName         string\n\tSeverity          Severity\n\tSeverityText      string\n\tBody              Value\n\tAttributes        []KeyValue\n}\n```\n\nThe bridge implementations could use [`sync.Pool`](https://pkg.go.dev/sync#Pool)\nfor reducing the number of allocations when passing attributes.\n\nThe benchmarks results were better.\n\nIn such a design, most bridges would have a `sync.Pool`\nto reduce the number of heap allocations.\nHowever, the `sync.Pool` will not work correctly with API implementations\nthat would take ownership of the record\n(e.g. implementations that do not copy records for asynchronous processing).\nThe current design, even in case of improper API implementation,\nhas lower  chances of encountering a bug as most bridges would\ncreate a record, pass it, and forget about it.\n\nFor reference, here is the reason why `slog` does not use `sync.Pool`[^3]\nas well:\n\n> We can use a sync pool for records though we decided not to.\nYou can but it's a bad idea for us. Why?\nBecause users have control of Records.\nHandler writers can get their hands on a record\nand we'd have to ask them to free it\nor try to free it magically at some some point.\nBut either way, they could get themselves in trouble by freeing it twice\nor holding on to one after they free it.\nThat's a use after free bug and that's why `zerolog` was problematic for us.\n`zerolog` as as part of its speed exposes a pool allocated value to users\nif you use `zerolog` the normal way, that you'll see in all the examples,\nyou will never encounter a problem.\nBut if you do something a little out of the ordinary you can get\nuse after free bugs and we just didn't want to put that in the standard library.\n\nTherefore, we decided to not follow the proposal as it is\nless user friendly (users and bridges would use e.g. a `sync.Pool` to reduce\nthe number of heap allocation), less safe (more prone to use after free bugs\nand race conditions), and the benchmark differences were not significant.\n\n### Use any instead of attribute.Value\n\n[Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)\ndefines Body to be `any`.\nOne could propose to define `Body` (and attribute values) as `any`\ninstead of using `attribute.Value`.\n\nFirst of all, [`any` type defined in the specification](https://opentelemetry.io/docs/specs/otel/logs/data-model/#type-any)\nis not the same as `any` (`interface{}`) in Go.\n\nMoreover, using `any` as a field would decrease the performance.[^7]\n\nUsing `attribute.Value` preserves a typed, allocation-conscious representation\nof the Logs Data Model `any` values while avoiding unconstrained `interface{}`\nhandling in bridge implementations.\n\n### Severity type encapsulating number and text\n\nWe could combine severity into a single field defining a type:\n\n```go\ntype Severity struct {\n\tNumber SeverityNumber\n\tText string\n}\n```\n\nHowever, the [Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#log-and-event-record-definition)\ndefine it as independent fields.\nIt should be more user friendly to have them separated.\nEspecially when having getter and setter methods, setting one value\nwhen the other is already set would be unpleasant.\n\n### Define log-specific value types\n\nThe original design defined `Kind`, `Value`, and `KeyValue` in\n`go.opentelemetry.io/otel/log`.\nThat avoided coupling log bodies to the common attribute package while logs were\nstill exploring structured value support.\n\nThe Logs Data Model and common attribute value model now share the structured\n`any` shapes needed by Go: empty, bool, int64, float64, string, byte slice,\nhomogeneous slices, generic slices, and maps.\nThe specification direction is to reuse these value shapes across signals.\nKeeping log-specific types would duplicate API surface, require conversion\nhelpers, and make bridge code choose between two equivalent value models.\n\nTherefore log records now use `attribute.Value` for body values and\n`attribute.KeyValue` for attributes and map entries.\n\n### Mix receiver types for Record\n\nMethods of [`slog.Record`](https://pkg.go.dev/log/slog#Record)\nhave different receiver types.\n\nIn `log/slog` GitHub issue we can only find that the reason is:[^8]\n\n>> some receiver of Record struct is by value\n> Passing Records by value means they incur no heap allocation.\n> That improves performance overall, even though they are copied.\n\nHowever, the benchmarks do not show any noticeable differences.[^9]\n\nThe compiler is smart-enough to not make a heap allocation for any of these methods.\nThe use of a pointer receiver does not cause any heap allocation.\nFrom Go FAQ:[^10]\n\n> In the current compilers, if a variable has its address taken,\n> that variable is a candidate for allocation on the heap.\n> However, a basic escape analysis recognizes some cases\n> when such variables will not live past the return from the function\n> and can reside on the stack.\n\nThe [Understanding Allocations: the Stack and the Heap](https://www.youtube.com/watch?v=ZMZpH4yT7M0)\npresentation by Jacob Walker describes the escape analysis with details.\n\nMoreover, also from Go FAQ:[^10]\n\n> Also, if a local variable is very large,\n> it might make more sense to store it on the heap rather than the stack.\n\nTherefore, even if we use a value receiver and the value is very large\nit may be heap allocated.\n\nBoth [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments#receiver-type)\nand [Google's Go Style Decisions](https://google.github.io/styleguide/go/decisions#receiver-type)\nhighly recommend making the methods for a type either all pointer methods\nor all value methods. Google's Go Style Decisions even goes further and says:\n\n> There is a lot of misinformation about whether passing a value or a pointer\n> to a function can affect performance.\n> The compiler can choose to pass pointers to values on the stack\n> as well as copying values on the stack,\n> but these considerations should not outweigh the readability\n> and correctness of the code in most circumstances.\n> When the performance does matter, it is important to profile both approaches\n> with a realistic benchmark before deciding that one approach outperforms the other.\n\nBecause, the benchmarks[^9] do not proof any performance difference\nand the general recommendation is to not mix receiver types,\nwe decided to use pointer receivers for all `Record` methods.\n\n### Add XYZ method to Logger\n\nThe `Logger` does not have methods like `SetSeverity`, etc.\nas the Logs API needs to follow (be compliant with)\nthe [specification](https://opentelemetry.io/docs/specs/otel/logs/api/)\n\n[^1]: [Handle structured body and attributes](https://github.com/pellared/opentelemetry-go/pull/7)\n[^2]: Jonathan Amsterdam, [The Go Blog: Structured Logging with slog](https://go.dev/blog/slog)\n[^3]: Jonathan Amsterdam, [GopherCon Europe 2023: A Fast Structured Logging Package](https://www.youtube.com/watch?v=tC4Jt3i62ns)\n[^4]: [Emit definition discussion with benchmarks](https://github.com/open-telemetry/opentelemetry-go/pull/4725#discussion_r1400869566)\n[^5]: [Logger.WithAttributes analysis](https://github.com/pellared/opentelemetry-go/pull/3)\n[^6]: [Record attributes as field and use sync.Pool for reducing allocations](https://github.com/pellared/opentelemetry-go/pull/4) and [Record attributes based on slog.Record](https://github.com/pellared/opentelemetry-go/pull/6)\n[^7]: [Record.Body as any](https://github.com/pellared/opentelemetry-go/pull/5)\n[^8]: [log/slog: structured, leveled logging](https://github.com/golang/go/issues/56345#issuecomment-1302563756)\n[^9]: [Record with pointer receivers only](https://github.com/pellared/opentelemetry-go/pull/8)\n[^10]: [Go FAQ: Stack or heap](https://go.dev/doc/faq#stack_or_heap)\n","AGENTS.md":"# Agent Guide for opentelemetry-go\n\nThis file contains active, task-oriented instructions for autonomous and semi-autonomous coding agents working in this repository.\n\nBefore starting any task, read `.github/copilot-instructions.md`, `CONTRIBUTING.md`, and this file.\nTreat `.github/copilot-instructions.md` as global passive guidance for every task, including docs-only and review-only work.\n\n## Core expectations\n\n- Preserve OpenTelemetry specification compliance, API stability, and idiomatic Go.\n- Prefer minimal, surgical changes over broad refactors or speculative cleanup.\n- Read the package you are editing and match its existing naming, option types, error handling, comments, tests, and concurrency patterns.\n- Keep public APIs backward compatible unless the task explicitly requires a breaking change.\n- Keep telemetry resilient and loosely coupled. Do not introduce behavior that can unexpectedly interfere with host applications.\n- Inspect boundaries carefully: input validation, resource limits, cancellation, shutdown, error propagation, concurrency, and memory growth.\n- Prefer fail-safe behavior and explicit invariants over implicit assumptions.\n- Keep dependencies minimal and justified.\n- Preserve host-application safety: telemetry should not panic, block indefinitely, or amplify attacker-controlled input.\n- Be conservative on hot paths. Avoid unnecessary allocations, reflection, interface churn, blocking, global state, and high-cardinality telemetry.\n- Write comments only for intent, invariants, and non-obvious constraints. Do not add comments that restate the code.\n\n## Default workflow\n\nFor new features and behavior changes, use this order unless the task explicitly says otherwise:\n\n1. Read the relevant package, its tests, and any package docs or `README.md`.\n2. Add or update a failing unit test that captures the required behavior or regression.\n3. Implement the smallest change that makes the test pass.\n4. Refactor only after the behavior is locked in, and only if the refactor keeps the diff focused.\n5. If the changed code is on a hot path or performance-sensitive, inspect existing benchmarks and run them. Add a benchmark if coverage is missing.\n6. Update documentation artifacts as needed while the context is fresh. Follow the documentation and changelog conventions below for the specific updates required.\n7. Run `make precommit` each time before considering the work complete.\n\nFor docs-only, test-only, or review-only tasks, still start with the required repository guidance above, then skip the workflow steps that do not apply while keeping the same discipline around scope, verification, and repository conventions.\n\n## Verification\n\n- Use `make` as the canonical repository verification command. The default target is `precommit`.\n- `make precommit` is the expected final verification step for linting, generation, README checks, module checks, and tests.\n- During iteration, targeted commands are fine for fast feedback, but do not stop there if the task changes code.\n- If you touch performance-sensitive code, run focused benchmarks and compare the results using `benchstat` in addition to `make`.\n\n## Documentation and changelog\n\n- Non-internal, non-test packages should have Go doc comments, usually in `doc.go`.\n- Non-internal, non-test, non-documentation packages should also have a `README.md` with at least a title and a `pkg.go.dev` badge.\n- Prefer examples over long code snippets in GoDoc when practical.\n- Keep docs aligned with actual behavior. Do not leave stale comments, stale examples, or stale package documentation behind.\n- For user-visible changes, update `CHANGELOG.md` under the appropriate `Added`, `Changed`, `Deprecated`, `Fixed`, or `Removed` section within `## [Unreleased]`.\n  - Always put the PR number at the end of the line (e.g., `(#1234)`), NOT the issue number.\n  - If the PR number is not yet known, omit it until the PR is created, then update the changelog entry before merging.\n  - Always use references to the go module that is updated (e.g., `go.opentelemetry.io/otel/sdk/metric`), instead of just the path (e.g., `sdk/metric`).\n\n## Repository habits\n\n- Prefer focused diffs. Avoid drive-by cleanup.\n- Follow existing option patterns and exported API conventions instead of inventing new abstractions.\n- Generated files are checked in. If your change affects generation, keep generated output up to date.\n- Prefer fast local search tools such as `rg` when exploring the repository.\n- When changing behavior, make the invariants explicit in tests.\n\n## Personas\n\n### Feature Agent\n\nUse this persona for new behavior, new API surface, or spec-driven feature work.\n\n- Start with a failing unit test.\n- Confirm the expected behavior against the spec, existing package behavior, and public API compatibility.\n- Implement the smallest viable change.\n- Update GoDoc, examples, `README.md`, and `CHANGELOG.md` when the change is user-visible.\n- If the feature touches a hot path, check benchmarks and add one if the coverage is missing.\n\n### Refactoring Agent\n\nUse this persona when improving structure without intentionally changing behavior.\n\n- Treat behavior preservation as the default contract.\n- Add or tighten tests before moving code if current behavior is not already pinned down.\n- Avoid broad rewrites, clever abstractions, or package-wide cleanup unless explicitly requested.\n- If a refactor touches a hot path, benchmark before and after.\n- Keep API shape, semantics, concurrency guarantees, and failure modes unchanged unless the task says otherwise.\n\n### Test Agent\n\nUse this persona when adding missing coverage, reproducing bugs, or hardening regressions.\n\n- Reproduce the bug or missing behavior with the smallest failing test you can.\n- Prefer testing public behavior and externally visible invariants.\n- Add targeted regression tests before changing production code.\n- Only change production code when it is required to make the tested behavior correct or testable.\n- Keep tests deterministic, readable, and aligned with package patterns.\n\n### Performance Agent\n\nUse this persona for hot-path work, allocation reduction, or throughput and latency improvements.\n\n- Benchmark first to establish a baseline.\n- Prefer changes that reduce allocations, copying, interface churn, and unnecessary synchronization.\n- Do not trade away correctness, spec compliance, or API stability for micro-optimizations.\n- Add or update benchmarks when performance-sensitive coverage is missing.\n- If you materially change a hot path, capture before-and-after results, preferably with `benchstat`.\n\n### Review Agent\n\nUse this persona when asked to review code, patches, or pull requests.\n\n- Lead with findings, not summaries.\n- Order findings by severity and include precise file and line references when available.\n- Focus on correctness, spec compliance, API compatibility, concurrency safety, resilience, performance regressions, missing tests, missing benchmarks, documentation gaps, and changelog gaps.\n- Call out when a diff is broader than necessary.\n- If you find no issues, say that explicitly and note any residual risks or verification gaps.\n",".github/copilot-instructions.md":"# Copilot instructions for opentelemetry-go\n\nThis repository is the Go implementation of OpenTelemetry. Prefer changes that preserve specification compliance, API stability, and idiomatic Go over clever abstractions or broad refactors.\n\n## Implementation rules\n\n- Read the package you are editing and follow its existing patterns for naming, options, error handling, comments, and tests.\n- Keep public APIs backward compatible unless the task explicitly requires a breaking change.\n- Follow the OpenTelemetry specification and semantic conventions. Match span, metric, log, attribute, event, resource, and instrumentation scope behavior to the spec and existing package behavior.\n- Prefer idiomatic Go and the repository's established patterns over inventing new abstractions.\n- Prefer minimal, surgical changes. Avoid requesting speculative flexibility, broad refactors, or unrelated cleanup when the diff can stay focused on the goal.\n- Prefer designs that keep telemetry easy to use and loosely coupled. Choose sensible defaults, avoid vendor-specific APIs or behavior, and do not force unrelated components to depend on each other.\n- For configurable constructors, reuse the project's usual option pattern: unexported `config` types, sealed `Option` interfaces with `apply`, and exported `With...` or `Without...` helpers.\n- Be conservative on hot paths. Avoid unnecessary allocations, reflection, interface churn, blocking, global state, and high-cardinality telemetry.\n- Preserve resilience and concurrency safety. Telemetry must not unexpectedly interfere with the host application; make lifecycle, synchronization, and failure-mode invariants explicit in code and tests.\n- Write comments only for intent, invariants, and non-obvious constraints. Do not add comments that restate the code.\n- Add or update tests for every behavior change. Add or update benchmarks for performance-sensitive changes.\n- Follow [CONTRIBUTING.md Design Choices](../CONTRIBUTING.md#design-choices).\n\n## Documentation and repository conventions\n\n- Non-internal, non-test packages should have Go doc comments, usually in `doc.go`.\n- Non-internal, non-test, non-documentation packages should also have a `README.md` with at least a title and `pkg.go.dev` badge.\n- If a change is user-visible, consider whether `CHANGELOG.md`, examples, package docs, or migration notes also need updates.\n"},"files":{"log/DESIGN.md":"# Logs API\n\n## Abstract\n\n`go.opentelemetry.io/otel/log` provides\n[Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/).\n\nThe prototype was created in\n[#4725](https://github.com/open-telemetry/opentelemetry-go/pull/4725).\n\n## Background\n\nThe key challenge is to create a performant API compliant with the [specification](https://opentelemetry.io/docs/specs/otel/logs/api/)\nwith an intuitive and user friendly design.\nPerformance is seen as one of the most important characteristics of logging libraries in Go.\n\n## Design\n\nThis proposed design aims to:\n\n- be specification compliant,\n- be similar to Trace and Metrics API,\n- take advantage of both OpenTelemetry and `slog` experience to achieve acceptable performance.\n\n### Module structure\n\nThe API is published as a single `go.opentelemetry.io/otel/log` Go module.\n\nThe package structure is similar to Trace API and Metrics API.\nThe Go module consists of the following packages:\n\n- `go.opentelemetry.io/otel/log`\n- `go.opentelemetry.io/otel/log/embedded`\n- `go.opentelemetry.io/otel/log/logtest`\n- `go.opentelemetry.io/otel/log/noop`\n\nRejected alternative:\n\n- [Reuse slog](#reuse-slog)\n\n### LoggerProvider\n\nThe [`LoggerProvider` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#loggerprovider)\nis defined as `LoggerProvider` interface in [provider.go](provider.go).\n\nThe specification may add new operations to `LoggerProvider`.\nThe interface may have methods added without a package major version bump.\nThis embeds `embedded.LoggerProvider` to help inform an API implementation\nauthor about this non-standard API evolution.\nThis approach is already used in Trace API and Metrics API.\n\n#### LoggerProvider.Logger\n\nThe `Logger` method implements the [`Get a Logger` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#get-a-logger).\n\nThe required `name` parameter is accepted as a `string` method argument.\n\nThe `LoggerOption` options are defined to support optional parameters.\n\nImplementation requirements:\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements)\n  the method to be safe to be called concurrently.\n\n- If the passed name is empty, this should be reported as invalid as specified\n  by the [Logs SDK specification](https://opentelemetry.io/docs/specs/otel/logs/sdk/#logger-creation).\n  The method should still use it as the instrumentation scope name and return\n  a working logger.\n\n`Logger` can be extended by adding new `LoggerOption` options\nand adding new exported fields to the `LoggerConfig` struct.\nThis design is already used in Trace API for getting tracers\nand in Metrics API for getting meters.\n\nRejected alternative:\n\n- [Passing struct as parameter to LoggerProvider.Logger](#passing-struct-as-parameter-to-loggerproviderlogger).\n\n### Logger\n\nThe [`Logger` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#logger)\nis defined as `Logger` interface in [logger.go](logger.go).\n\nThe specification may add new operations to `Logger`.\nThe interface may have methods added without a package major version bump.\nThis embeds `embedded.Logger` to help inform an API implementation\nauthor about this non-standard API evolution.\nThis approach is already used in Trace API and Metrics API.\n\n### Logger.Emit\n\nThe `Emit` method implements the [`Emit a LogRecord` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord).\n\n[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)\nis accepted as a `context.Context` method argument.\n\nCalls to `Emit` are supposed to be on the hot path.\nTherefore, in order to reduce the number of heap allocations,\nthe [`LogRecord` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord),\nis defined as `Record` struct  in [record.go](record.go).\n\n[`Timestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-timestamp)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Timestamp() time.Time\nfunc (r *Record) SetTimestamp(t time.Time)\n```\n\n[`ObservedTimestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-observedtimestamp)\nis accessed using following methods:\n\n```go\nfunc (r *Record) ObservedTimestamp() time.Time\nfunc (r *Record) SetObservedTimestamp(t time.Time)\n```\n\n[`EventName`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-eventname)\nis accessed using following methods:\n\n```go\nfunc (r *Record) EventName() string\nfunc (r *Record) SetEventName(s string)\n```\n\n[`SeverityNumber`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Severity() Severity\nfunc (r *Record) SetSeverity(s Severity)\n```\n\n`Severity` type is defined in [severity.go](severity.go).\nThe constants are are based on\n[Displaying Severity recommendation](https://opentelemetry.io/docs/specs/otel/logs/data-model/#displaying-severity).\nAdditionally, `Severity[Level]` constants are defined to make the API more readable and user friendly.\n\n[`SeverityText`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext)\nis accessed using following methods:\n\n```go\nfunc (r *Record) SeverityText() string\nfunc (r *Record) SetSeverityText(s string)\n```\n\n[`Body`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Body() attribute.Value\nfunc (r *Record) SetBody(v attribute.Value)\n```\n\n[Log record attributes](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-attributes)\nare accessed using following methods:\n\n```go\nfunc (r *Record) WalkAttributes(f func(attribute.KeyValue) bool)\nfunc (r *Record) AddAttributes(attrs ...attribute.KeyValue)\n```\n\n`Record` has a `AttributesLen` method that returns\nthe number of attributes to allow slice preallocation\nwhen converting records to a different representation:\n\n```go\nfunc (r *Record) AttributesLen() int\n```\n\nThe records attributes design and implementation is based on\n[`slog.Record`](https://pkg.go.dev/log/slog#Record).\nIt allows achieving high-performance access and manipulation of the attributes\nwhile keeping the API user friendly.\nIt relieves the user from making his own improvements\nfor reducing the number of allocations when passing attributes.\n\nLog body and attributes use the common\n[`attribute.Value`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#Value)\nand\n[`attribute.KeyValue`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#KeyValue)\ntypes.\nThese types cover the Logs Data Model `any` value shape, including empty\nvalues, byte slices, generic slices, and maps.\nReusing the attribute package keeps the API consistent across signals and\navoids maintaining a second value model with conversion helpers.\n\nThe zero value of `attribute.Value` represents an empty body.\nLog maps use `attribute.MAP`, which may contain duplicate keys when callers\nconstruct one that way. Duplicate-key normalization is an SDK policy, not an\nAPI behavior.\n\nThe caller must not subsequently mutate the record passed to `Emit`.\nThis would allow the implementation to not clone the record,\nbut simply retain, modify or discard it.\nThe implementation may still choose to clone the record or copy its attributes\nif it needs to retain or modify it,\ne.g. in case of asynchronous processing to eliminate the possibility of data races,\nbecause the user can technically reuse the record and add new attributes\nafter the call (even when the documentation says that the caller must not do it).\n\nImplementation requirements:\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements)\n  the method to be safe to be called concurrently.\n\n- The method must not interrupt the record processing if the context is canceled\n  per [\"ignoring context cancellation\" guideline](../CONTRIBUTING.md#ignoring-context-cancellation).\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord)\n  use the current time as observed timestamp if the passed is empty.\n\n- The method should handle the trace context passed via `ctx` argument in order to meet the\n  [specification's SDK requirement](https://opentelemetry.io/docs/specs/otel/logs/sdk/#readablelogrecord)\n  to populate the trace context fields from the resolved context.\n\n`Emit` can be extended by adding new exported fields to the `Record` struct.\n\nRejected alternatives:\n\n- [Record as interface](#record-as-interface)\n- [Options as parameter to Logger.Emit](#options-as-parameter-to-loggeremit)\n- [Passing record as pointer to Logger.Emit](#passing-record-as-pointer-to-loggeremit)\n- [Logger.WithAttributes](#loggerwithattributes)\n- [Record attributes as slice](#record-attributes-as-slice)\n- [Use any instead of attribute.Value](#use-any-instead-of-attributevalue)\n- [Severity type encapsulating number and text](#severity-type-encapsulating-number-and-text)\n- [Define log-specific value types](#define-log-specific-value-types)\n- [Mix receiver types for Record](#mix-receiver-types-for-record)\n- [Add XYZ method to Logger](#add-xyz-method-to-logger)\n\n### Logger.Enabled\n\nThe `Enabled` method implements the [`Enabled` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#enabled).\n\n[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)\nis accepted as a `context.Context` method argument.\n\nCalls to `Enabled` are supposed to be on the hot path and the list of arguments\ncan be extendend in future. Therefore, in order to reduce the number of heap\nallocations and make it possible to handle new arguments, `Enabled` accepts\na `EnabledParameters` struct, defined in [logger.go](logger.go), as the second\nmethod argument.\n\nThe `EnabledParameters` uses fields, instead of getters and setters, to allow\nsimpler usage which allows configuring the `EnabledParameters` in the same line\nwhere `Enabled` is called.\n\n### noop package\n\nThe `go.opentelemetry.io/otel/log/noop` package provides\n[Logs API No-Op Implementation](https://opentelemetry.io/docs/specs/otel/logs/noop/).\n\n### Trace context correlation\n\nThe bridge implementation should do its best to pass\nthe `ctx` containing the trace context from the caller\nso it can later be passed via `Logger.Emit`.\n\nIt is not expected that users (caller or bridge implementation) reconstruct\na `context.Context`. Reconstructing a `context.Context` with\n[`trace.ContextWithSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#ContextWithSpanContext)\nand [`trace.NewSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#NewSpanContext)\nwould usually involve more memory allocations.\n\nThe logging libraries which have recording methods that accepts `context.Context`,\nsuch us [`slog`](https://pkg.go.dev/log/slog),\n[`logrus`](https://pkg.go.dev/github.com/sirupsen/logrus),\n[`zerolog`](https://pkg.go.dev/github.com/rs/zerolog),\nmakes passing the trace context trivial.\n\nHowever, some libraries do not accept a `context.Context` in their recording methods.\nStructured logging libraries,\nsuch as [`logr`](https://pkg.go.dev/github.com/go-logr/logr)\nand [`zap`](https://pkg.go.dev/go.uber.org/zap),\noffer passing `any` type as a log attribute/field.\nTherefore, their bridge implementations can define a \"special\" log attributes/field\nthat will be used to capture the trace context.\n\n[The prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725)\nhas bridge implementations that handle trace context correlation efficiently.\n\n## Benchmarking\n\nThe benchmarks take inspiration from [`slog`](https://pkg.go.dev/log/slog),\nbecause for the Go team it was also critical to create API that would be fast\nand interoperable with existing logging packages.[^2][^3]\n\nThe benchmark results can be found in [the prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725).\n\n## Rejected alternatives\n\n### Reuse slog\n\nThe API must not be coupled to [`slog`](https://pkg.go.dev/log/slog),\nnor any other logging library.\n\nThe API needs to evolve orthogonally to `slog`.\n\n`slog` is not compliant with the [Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/).\nand we cannot expect the Go team to make `slog` compliant with it.\n\nThe interoperability can be achieved using [a log bridge](https://opentelemetry.io/docs/specs/otel/glossary/#log-appender--bridge).\n\nYou can read more about OpenTelemetry Logs design on [opentelemetry.io](https://opentelemetry.io/docs/concepts/signals/logs/).\n\n### Record as interface\n\n`Record` is defined as a `struct` because of the following reasons.\n\nLog record is a value object without any behavior.\nIt is used as data input for Logger methods.\n\nThe log record resembles the instrument config structs like [metric.Float64CounterConfig](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Float64CounterConfig).\n\nUsing `struct` instead of `interface` improves the performance as e.g.\nindirect calls are less optimized,\nusage of interfaces tend to increase heap allocations.[^3]\n\n### Options as parameter to Logger.Emit\n\nOne of the initial ideas was to have:\n\n```go\ntype Logger interface{\n\tembedded.Logger\n\tEmit(ctx context.Context, options ...RecordOption)\n}\n```\n\nThe main reason was that design would be similar\nto the [Meter API](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Meter)\nfor creating instruments.\n\nHowever, passing `Record` directly, instead of using options,\nis more performant as it reduces heap allocations.[^4]\n\nAnother advantage of passing `Record` is that API would not have functions like `NewRecord(options...)`,\nwhich would be used by the SDK and not by the users.\n\nFinally, the definition would be similar to [`slog.Handler.Handle`](https://pkg.go.dev/log/slog#Handler)\nthat was designed to provide optimization opportunities.[^2]\n\n### Passing record as pointer to Logger.Emit\n\nSo far the benchmarks do not show differences that would\nfavor passing the record via pointer (and vice versa).\n\nPassing via value feels safer because of the following reasons.\n\nThe user would not be able to pass `nil`.\nTherefore, it reduces the possibility to have a nil pointer dereference.\n\nIt should reduce the possibility of a heap allocation.\n\nIt follows the design of [`slog.Handler`](https://pkg.go.dev/log/slog#Handler).\n\nIf follows one of Google's Go Style Decisions\nto prefer [passing values](https://google.github.io/styleguide/go/decisions#pass-values).\n\n### Passing struct as parameter to LoggerProvider.Logger\n\nSimilarly to `Logger.Emit`, we could have something like:\n\n```go\ntype LoggerProvider interface{\n\tembedded.LoggerProvider\n\tLogger(name string, config LoggerConfig)\n}\n```\n\nThe drawback of this idea would be that this would be\na different design from Trace and Metrics API.\n\nThe performance of acquiring a logger is not as critical\nas the performance of emitting a log record. While a single\nHTTP/RPC handler could write hundreds of logs, it should not\ncreate a new logger for each log entry.\nThe bridge implementation should reuse loggers whenever possible.\n\n### Logger.WithAttributes\n\nWe could add `WithAttributes` to the `Logger` interface.\nThen `Record` could be a simple struct with only exported fields.\nThe idea was that the SDK would implement the performance improvements\ninstead of doing it in the API.\nThis would allow having different optimization strategies.\n\nDuring the analysis[^5], it occurred that the main problem of this proposal\nis that the variadic slice passed to an interface method is always heap allocated.\n\nMoreover, the logger returned by `WithAttribute` was allocated on the heap.\n\nLastly, the proposal was not specification compliant.\n\n### Record attributes as slice\n\nOne of the proposals[^6] was to have `Record` as a simple struct:\n\n```go\ntype Record struct {\n\tTimestamp         time.Time\n\tObservedTimestamp time.Time\n\tEventName         string\n\tSeverity          Severity\n\tSeverityText      string\n\tBody              Value\n\tAttributes        []KeyValue\n}\n```\n\nThe bridge implementations could use [`sync.Pool`](https://pkg.go.dev/sync#Pool)\nfor reducing the number of allocations when passing attributes.\n\nThe benchmarks results were better.\n\nIn such a design, most bridges would have a `sync.Pool`\nto reduce the number of heap allocations.\nHowever, the `sync.Pool` will not work correctly with API implementations\nthat would take ownership of the record\n(e.g. implementations that do not copy records for asynchronous processing).\nThe current design, even in case of improper API implementation,\nhas lower  chances of encountering a bug as most bridges would\ncreate a record, pass it, and forget about it.\n\nFor reference, here is the reason why `slog` does not use `sync.Pool`[^3]\nas well:\n\n> We can use a sync pool for records though we decided not to.\nYou can but it's a bad idea for us. Why?\nBecause users have control of Records.\nHandler writers can get their hands on a record\nand we'd have to ask them to free it\nor try to free it magically at some some point.\nBut either way, they could get themselves in trouble by freeing it twice\nor holding on to one after they free it.\nThat's a use after free bug and that's why `zerolog` was problematic for us.\n`zerolog` as as part of its speed exposes a pool allocated value to users\nif you use `zerolog` the normal way, that you'll see in all the examples,\nyou will never encounter a problem.\nBut if you do something a little out of the ordinary you can get\nuse after free bugs and we just didn't want to put that in the standard library.\n\nTherefore, we decided to not follow the proposal as it is\nless user friendly (users and bridges would use e.g. a `sync.Pool` to reduce\nthe number of heap allocation), less safe (more prone to use after free bugs\nand race conditions), and the benchmark differences were not significant.\n\n### Use any instead of attribute.Value\n\n[Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)\ndefines Body to be `any`.\nOne could propose to define `Body` (and attribute values) as `any`\ninstead of using `attribute.Value`.\n\nFirst of all, [`any` type defined in the specification](https://opentelemetry.io/docs/specs/otel/logs/data-model/#type-any)\nis not the same as `any` (`interface{}`) in Go.\n\nMoreover, using `any` as a field would decrease the performance.[^7]\n\nUsing `attribute.Value` preserves a typed, allocation-conscious representation\nof the Logs Data Model `any` values while avoiding unconstrained `interface{}`\nhandling in bridge implementations.\n\n### Severity type encapsulating number and text\n\nWe could combine severity into a single field defining a type:\n\n```go\ntype Severity struct {\n\tNumber SeverityNumber\n\tText string\n}\n```\n\nHowever, the [Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#log-and-event-record-definition)\ndefine it as independent fields.\nIt should be more user friendly to have them separated.\nEspecially when having getter and setter methods, setting one value\nwhen the other is already set would be unpleasant.\n\n### Define log-specific value types\n\nThe original design defined `Kind`, `Value`, and `KeyValue` in\n`go.opentelemetry.io/otel/log`.\nThat avoided coupling log bodies to the common attribute package while logs were\nstill exploring structured value support.\n\nThe Logs Data Model and common attribute value model now share the structured\n`any` shapes needed by Go: empty, bool, int64, float64, string, byte slice,\nhomogeneous slices, generic slices, and maps.\nThe specification direction is to reuse these value shapes across signals.\nKeeping log-specific types would duplicate API surface, require conversion\nhelpers, and make bridge code choose between two equivalent value models.\n\nTherefore log records now use `attribute.Value` for body values and\n`attribute.KeyValue` for attributes and map entries.\n\n### Mix receiver types for Record\n\nMethods of [`slog.Record`](https://pkg.go.dev/log/slog#Record)\nhave different receiver types.\n\nIn `log/slog` GitHub issue we can only find that the reason is:[^8]\n\n>> some receiver of Record struct is by value\n> Passing Records by value means they incur no heap allocation.\n> That improves performance overall, even though they are copied.\n\nHowever, the benchmarks do not show any noticeable differences.[^9]\n\nThe compiler is smart-enough to not make a heap allocation for any of these methods.\nThe use of a pointer receiver does not cause any heap allocation.\nFrom Go FAQ:[^10]\n\n> In the current compilers, if a variable has its address taken,\n> that variable is a candidate for allocation on the heap.\n> However, a basic escape analysis recognizes some cases\n> when such variables will not live past the return from the function\n> and can reside on the stack.\n\nThe [Understanding Allocations: the Stack and the Heap](https://www.youtube.com/watch?v=ZMZpH4yT7M0)\npresentation by Jacob Walker describes the escape analysis with details.\n\nMoreover, also from Go FAQ:[^10]\n\n> Also, if a local variable is very large,\n> it might make more sense to store it on the heap rather than the stack.\n\nTherefore, even if we use a value receiver and the value is very large\nit may be heap allocated.\n\nBoth [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments#receiver-type)\nand [Google's Go Style Decisions](https://google.github.io/styleguide/go/decisions#receiver-type)\nhighly recommend making the methods for a type either all pointer methods\nor all value methods. Google's Go Style Decisions even goes further and says:\n\n> There is a lot of misinformation about whether passing a value or a pointer\n> to a function can affect performance.\n> The compiler can choose to pass pointers to values on the stack\n> as well as copying values on the stack,\n> but these considerations should not outweigh the readability\n> and correctness of the code in most circumstances.\n> When the performance does matter, it is important to profile both approaches\n> with a realistic benchmark before deciding that one approach outperforms the other.\n\nBecause, the benchmarks[^9] do not proof any performance difference\nand the general recommendation is to not mix receiver types,\nwe decided to use pointer receivers for all `Record` methods.\n\n### Add XYZ method to Logger\n\nThe `Logger` does not have methods like `SetSeverity`, etc.\nas the Logs API needs to follow (be compliant with)\nthe [specification](https://opentelemetry.io/docs/specs/otel/logs/api/)\n\n[^1]: [Handle structured body and attributes](https://github.com/pellared/opentelemetry-go/pull/7)\n[^2]: Jonathan Amsterdam, [The Go Blog: Structured Logging with slog](https://go.dev/blog/slog)\n[^3]: Jonathan Amsterdam, [GopherCon Europe 2023: A Fast Structured Logging Package](https://www.youtube.com/watch?v=tC4Jt3i62ns)\n[^4]: [Emit definition discussion with benchmarks](https://github.com/open-telemetry/opentelemetry-go/pull/4725#discussion_r1400869566)\n[^5]: [Logger.WithAttributes analysis](https://github.com/pellared/opentelemetry-go/pull/3)\n[^6]: [Record attributes as field and use sync.Pool for reducing allocations](https://github.com/pellared/opentelemetry-go/pull/4) and [Record attributes based on slog.Record](https://github.com/pellared/opentelemetry-go/pull/6)\n[^7]: [Record.Body as any](https://github.com/pellared/opentelemetry-go/pull/5)\n[^8]: [log/slog: structured, leveled logging](https://github.com/golang/go/issues/56345#issuecomment-1302563756)\n[^9]: [Record with pointer receivers only](https://github.com/pellared/opentelemetry-go/pull/8)\n[^10]: [Go FAQ: Stack or heap](https://go.dev/doc/faq#stack_or_heap)\n","AGENTS.md":"# Agent Guide for opentelemetry-go\n\nThis file contains active, task-oriented instructions for autonomous and semi-autonomous coding agents working in this repository.\n\nBefore starting any task, read `.github/copilot-instructions.md`, `CONTRIBUTING.md`, and this file.\nTreat `.github/copilot-instructions.md` as global passive guidance for every task, including docs-only and review-only work.\n\n## Core expectations\n\n- Preserve OpenTelemetry specification compliance, API stability, and idiomatic Go.\n- Prefer minimal, surgical changes over broad refactors or speculative cleanup.\n- Read the package you are editing and match its existing naming, option types, error handling, comments, tests, and concurrency patterns.\n- Keep public APIs backward compatible unless the task explicitly requires a breaking change.\n- Keep telemetry resilient and loosely coupled. Do not introduce behavior that can unexpectedly interfere with host applications.\n- Inspect boundaries carefully: input validation, resource limits, cancellation, shutdown, error propagation, concurrency, and memory growth.\n- Prefer fail-safe behavior and explicit invariants over implicit assumptions.\n- Keep dependencies minimal and justified.\n- Preserve host-application safety: telemetry should not panic, block indefinitely, or amplify attacker-controlled input.\n- Be conservative on hot paths. Avoid unnecessary allocations, reflection, interface churn, blocking, global state, and high-cardinality telemetry.\n- Write comments only for intent, invariants, and non-obvious constraints. Do not add comments that restate the code.\n\n## Default workflow\n\nFor new features and behavior changes, use this order unless the task explicitly says otherwise:\n\n1. Read the relevant package, its tests, and any package docs or `README.md`.\n2. Add or update a failing unit test that captures the required behavior or regression.\n3. Implement the smallest change that makes the test pass.\n4. Refactor only after the behavior is locked in, and only if the refactor keeps the diff focused.\n5. If the changed code is on a hot path or performance-sensitive, inspect existing benchmarks and run them. Add a benchmark if coverage is missing.\n6. Update documentation artifacts as needed while the context is fresh. Follow the documentation and changelog conventions below for the specific updates required.\n7. Run `make precommit` each time before considering the work complete.\n\nFor docs-only, test-only, or review-only tasks, still start with the required repository guidance above, then skip the workflow steps that do not apply while keeping the same discipline around scope, verification, and repository conventions.\n\n## Verification\n\n- Use `make` as the canonical repository verification command. The default target is `precommit`.\n- `make precommit` is the expected final verification step for linting, generation, README checks, module checks, and tests.\n- During iteration, targeted commands are fine for fast feedback, but do not stop there if the task changes code.\n- If you touch performance-sensitive code, run focused benchmarks and compare the results using `benchstat` in addition to `make`.\n\n## Documentation and changelog\n\n- Non-internal, non-test packages should have Go doc comments, usually in `doc.go`.\n- Non-internal, non-test, non-documentation packages should also have a `README.md` with at least a title and a `pkg.go.dev` badge.\n- Prefer examples over long code snippets in GoDoc when practical.\n- Keep docs aligned with actual behavior. Do not leave stale comments, stale examples, or stale package documentation behind.\n- For user-visible changes, update `CHANGELOG.md` under the appropriate `Added`, `Changed`, `Deprecated`, `Fixed`, or `Removed` section within `## [Unreleased]`.\n  - Always put the PR number at the end of the line (e.g., `(#1234)`), NOT the issue number.\n  - If the PR number is not yet known, omit it until the PR is created, then update the changelog entry before merging.\n  - Always use references to the go module that is updated (e.g., `go.opentelemetry.io/otel/sdk/metric`), instead of just the path (e.g., `sdk/metric`).\n\n## Repository habits\n\n- Prefer focused diffs. Avoid drive-by cleanup.\n- Follow existing option patterns and exported API conventions instead of inventing new abstractions.\n- Generated files are checked in. If your change affects generation, keep generated output up to date.\n- Prefer fast local search tools such as `rg` when exploring the repository.\n- When changing behavior, make the invariants explicit in tests.\n\n## Personas\n\n### Feature Agent\n\nUse this persona for new behavior, new API surface, or spec-driven feature work.\n\n- Start with a failing unit test.\n- Confirm the expected behavior against the spec, existing package behavior, and public API compatibility.\n- Implement the smallest viable change.\n- Update GoDoc, examples, `README.md`, and `CHANGELOG.md` when the change is user-visible.\n- If the feature touches a hot path, check benchmarks and add one if the coverage is missing.\n\n### Refactoring Agent\n\nUse this persona when improving structure without intentionally changing behavior.\n\n- Treat behavior preservation as the default contract.\n- Add or tighten tests before moving code if current behavior is not already pinned down.\n- Avoid broad rewrites, clever abstractions, or package-wide cleanup unless explicitly requested.\n- If a refactor touches a hot path, benchmark before and after.\n- Keep API shape, semantics, concurrency guarantees, and failure modes unchanged unless the task says otherwise.\n\n### Test Agent\n\nUse this persona when adding missing coverage, reproducing bugs, or hardening regressions.\n\n- Reproduce the bug or missing behavior with the smallest failing test you can.\n- Prefer testing public behavior and externally visible invariants.\n- Add targeted regression tests before changing production code.\n- Only change production code when it is required to make the tested behavior correct or testable.\n- Keep tests deterministic, readable, and aligned with package patterns.\n\n### Performance Agent\n\nUse this persona for hot-path work, allocation reduction, or throughput and latency improvements.\n\n- Benchmark first to establish a baseline.\n- Prefer changes that reduce allocations, copying, interface churn, and unnecessary synchronization.\n- Do not trade away correctness, spec compliance, or API stability for micro-optimizations.\n- Add or update benchmarks when performance-sensitive coverage is missing.\n- If you materially change a hot path, capture before-and-after results, preferably with `benchstat`.\n\n### Review Agent\n\nUse this persona when asked to review code, patches, or pull requests.\n\n- Lead with findings, not summaries.\n- Order findings by severity and include precise file and line references when available.\n- Focus on correctness, spec compliance, API compatibility, concurrency safety, resilience, performance regressions, missing tests, missing benchmarks, documentation gaps, and changelog gaps.\n- Call out when a diff is broader than necessary.\n- If you find no issues, say that explicitly and note any residual risks or verification gaps.\n",".github/copilot-instructions.md":"# Copilot instructions for opentelemetry-go\n\nThis repository is the Go implementation of OpenTelemetry. Prefer changes that preserve specification compliance, API stability, and idiomatic Go over clever abstractions or broad refactors.\n\n## Implementation rules\n\n- Read the package you are editing and follow its existing patterns for naming, options, error handling, comments, and tests.\n- Keep public APIs backward compatible unless the task explicitly requires a breaking change.\n- Follow the OpenTelemetry specification and semantic conventions. Match span, metric, log, attribute, event, resource, and instrumentation scope behavior to the spec and existing package behavior.\n- Prefer idiomatic Go and the repository's established patterns over inventing new abstractions.\n- Prefer minimal, surgical changes. Avoid requesting speculative flexibility, broad refactors, or unrelated cleanup when the diff can stay focused on the goal.\n- Prefer designs that keep telemetry easy to use and loosely coupled. Choose sensible defaults, avoid vendor-specific APIs or behavior, and do not force unrelated components to depend on each other.\n- For configurable constructors, reuse the project's usual option pattern: unexported `config` types, sealed `Option` interfaces with `apply`, and exported `With...` or `Without...` helpers.\n- Be conservative on hot paths. Avoid unnecessary allocations, reflection, interface churn, blocking, global state, and high-cardinality telemetry.\n- Preserve resilience and concurrency safety. Telemetry must not unexpectedly interfere with the host application; make lifecycle, synchronization, and failure-mode invariants explicit in code and tests.\n- Write comments only for intent, invariants, and non-obvious constraints. Do not add comments that restate the code.\n- Add or update tests for every behavior change. Add or update benchmarks for performance-sensitive changes.\n- Follow [CONTRIBUTING.md Design Choices](../CONTRIBUTING.md#design-choices).\n\n## Documentation and repository conventions\n\n- Non-internal, non-test packages should have Go doc comments, usually in `doc.go`.\n- Non-internal, non-test, non-documentation packages should also have a `README.md` with at least a title and `pkg.go.dev` badge.\n- If a change is user-visible, consider whether `CHANGELOG.md`, examples, package docs, or migration notes also need updates.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/open-telemetry/opentelemetry-go/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Agent Guide for opentelemetry-go\n\nThis file contains active, task-oriented instructions for autonomous and semi-autonomous coding agents working in this repository.\n\nBefore starting any task, read `.github/copilot-instructions.md`, `CONTRIBUTING.md`, and this file.\nTreat `.github/copilot-instructions.md` as global passive guidance for every task, including docs-only and review-only work.\n\n## Core expectations\n\n- Preserve OpenTelemetry specification compliance, API stability, and idiomatic Go.\n- Prefer minimal, surgical changes over broad refactors or speculative cleanup.\n- Read the package you are editing and match its existing naming, option types, error handling, comments, tests, and concurrency patterns.\n- Keep public APIs backward compatible unless the task explicitly requires a breaking change.\n- Keep telemetry resilient and loosely coupled. Do not introduce behavior that can unexpectedly interfere with host applications.\n- Inspect boundaries carefully: input validation, resource limits, cancellation, shutdown, error propagation, concurrency, and memory growth.\n- Prefer fail-safe behavior and explicit invariants over implicit assumptions.\n- Keep dependencies minimal and justified.\n- Preserve host-application safety: telemetry should not panic, block indefinitely, or amplify attacker-controlled input.\n- Be conservative on hot paths. Avoid unnecessary allocations, reflection, interface churn, blocking, global state, and high-cardinality telemetry.\n- Write comments only for intent, invariants, and non-obvious constraints. Do not add comments that restate the code.\n\n## Default workflow\n\nFor new features and behavior changes, use this order unless the task explicitly says otherwise:\n\n1. Read the relevant package, its tests, and any package docs or `README.md`.\n2. Add or update a failing unit test that captures the required behavior or regression.\n3. Implement the smallest change that makes the test pass.\n4. Refactor only after the behavior is locked in, and only if the refactor keeps the diff focused.\n5. If the changed code is on a hot path or performance-sensitive, inspect existing benchmarks and run them. Add a benchmark if coverage is missing.\n6. Update documentation artifacts as needed while the context is fresh. Follow the documentation and changelog conventions below for the specific updates required.\n7. Run `make precommit` each time before considering the work complete.\n\nFor docs-only, test-only, or review-only tasks, still start with the required repository guidance above, then skip the workflow steps that do not apply while keeping the same discipline around scope, verification, and repository conventions.\n\n## Verification\n\n- Use `make` as the canonical repository verification command. The default target is `precommit`.\n- `make precommit` is the expected final verification step for linting, generation, README checks, module checks, and tests.\n- During iteration, targeted commands are fine for fast feedback, but do not stop there if the task changes code.\n- If you touch performance-sensitive code, run focused benchmarks and compare the results using `benchstat` in addition to `make`.\n\n## Documentation and changelog\n\n- Non-internal, non-test packages should have Go doc comments, usually in `doc.go`.\n- Non-internal, non-test, non-documentation packages should also have a `README.md` with at least a title and a `pkg.go.dev` badge.\n- Prefer examples over long code snippets in GoDoc when practical.\n- Keep docs aligned with actual behavior. Do not leave stale comments, stale examples, or stale package documentation behind.\n- For user-visible changes, update `CHANGELOG.md` under the appropriate `Added`, `Changed`, `Deprecated`, `Fixed`, or `Removed` section within `## [Unreleased]`.\n  - Always put the PR number at the end of the line (e.g., `(#1234)`), NOT the issue number.\n  - If the PR number is not yet known, omit it until the PR is created, then update the changelog entry before merging.\n  - Always use references to the go module that is updated (e.g., `go.opentelemetry.io/otel/sdk/metric`), instead of just the path (e.g., `sdk/metric`).\n\n## Repository habits\n\n- Prefer focused diffs. Avoid drive-by cleanup.\n- Follow existing option patterns and exported API conventions instead of inventing new abstractions.\n- Generated files are checked in. If your change affects generation, keep generated output up to date.\n- Prefer fast local search tools such as `rg` when exploring the repository.\n- When changing behavior, make the invariants explicit in tests.\n\n## Personas\n\n### Feature Agent\n\nUse this persona for new behavior, new API surface, or spec-driven feature work.\n\n- Start with a failing unit test.\n- Confirm the expected behavior against the spec, existing package behavior, and public API compatibility.\n- Implement the smallest viable change.\n- Update GoDoc, examples, `README.md`, and `CHANGELOG.md` when the change is user-visible.\n- If the feature touches a hot path, check benchmarks and add one if the coverage is missing.\n\n### Refactoring Agent\n\nUse this persona when improving structure without intentionally changing behavior.\n\n- Treat behavior preservation as the default contract.\n- Add or tighten tests before moving code if current behavior is not already pinned down.\n- Avoid broad rewrites, clever abstractions, or package-wide cleanup unless explicitly requested.\n- If a refactor touches a hot path, benchmark before and after.\n- Keep API shape, semantics, concurrency guarantees, and failure modes unchanged unless the task says otherwise.\n\n### Test Agent\n\nUse this persona when adding missing coverage, reproducing bugs, or hardening regressions.\n\n- Reproduce the bug or missing behavior with the smallest failing test you can.\n- Prefer testing public behavior and externally visible invariants.\n- Add targeted regression tests before changing production code.\n- Only change production code when it is required to make the tested behavior correct or testable.\n- Keep tests deterministic, readable, and aligned with package patterns.\n\n### Performance Agent\n\nUse this persona for hot-path work, allocation reduction, or throughput and latency improvements.\n\n- Benchmark first to establish a baseline.\n- Prefer changes that reduce allocations, copying, interface churn, and unnecessary synchronization.\n- Do not trade away correctness, spec compliance, or API stability for micro-optimizations.\n- Add or update benchmarks when performance-sensitive coverage is missing.\n- If you materially change a hot path, capture before-and-after results, preferably with `benchstat`.\n\n### Review Agent\n\nUse this persona when asked to review code, patches, or pull requests.\n\n- Lead with findings, not summaries.\n- Order findings by severity and include precise file and line references when available.\n- Focus on correctness, spec compliance, API compatibility, concurrency safety, resilience, performance regressions, missing tests, missing benchmarks, documentation gaps, and changelog gaps.\n- Call out when a diff is broader than necessary.\n- If you find no issues, say that explicitly and note any residual risks or verification gaps.\n","isInternal":false,"tokens":1408,"sizeBytes":7134},{"name":"DESIGN.md","path":"log/DESIGN.md","rawUrl":"https://raw.githubusercontent.com/open-telemetry/opentelemetry-go/HEAD/log/DESIGN.md","title":"log - UI Design System & Style Tokens","category":"project-spec","format":"markdown","content":"# Logs API\n\n## Abstract\n\n`go.opentelemetry.io/otel/log` provides\n[Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/).\n\nThe prototype was created in\n[#4725](https://github.com/open-telemetry/opentelemetry-go/pull/4725).\n\n## Background\n\nThe key challenge is to create a performant API compliant with the [specification](https://opentelemetry.io/docs/specs/otel/logs/api/)\nwith an intuitive and user friendly design.\nPerformance is seen as one of the most important characteristics of logging libraries in Go.\n\n## Design\n\nThis proposed design aims to:\n\n- be specification compliant,\n- be similar to Trace and Metrics API,\n- take advantage of both OpenTelemetry and `slog` experience to achieve acceptable performance.\n\n### Module structure\n\nThe API is published as a single `go.opentelemetry.io/otel/log` Go module.\n\nThe package structure is similar to Trace API and Metrics API.\nThe Go module consists of the following packages:\n\n- `go.opentelemetry.io/otel/log`\n- `go.opentelemetry.io/otel/log/embedded`\n- `go.opentelemetry.io/otel/log/logtest`\n- `go.opentelemetry.io/otel/log/noop`\n\nRejected alternative:\n\n- [Reuse slog](#reuse-slog)\n\n### LoggerProvider\n\nThe [`LoggerProvider` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#loggerprovider)\nis defined as `LoggerProvider` interface in [provider.go](provider.go).\n\nThe specification may add new operations to `LoggerProvider`.\nThe interface may have methods added without a package major version bump.\nThis embeds `embedded.LoggerProvider` to help inform an API implementation\nauthor about this non-standard API evolution.\nThis approach is already used in Trace API and Metrics API.\n\n#### LoggerProvider.Logger\n\nThe `Logger` method implements the [`Get a Logger` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#get-a-logger).\n\nThe required `name` parameter is accepted as a `string` method argument.\n\nThe `LoggerOption` options are defined to support optional parameters.\n\nImplementation requirements:\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements)\n  the method to be safe to be called concurrently.\n\n- If the passed name is empty, this should be reported as invalid as specified\n  by the [Logs SDK specification](https://opentelemetry.io/docs/specs/otel/logs/sdk/#logger-creation).\n  The method should still use it as the instrumentation scope name and return\n  a working logger.\n\n`Logger` can be extended by adding new `LoggerOption` options\nand adding new exported fields to the `LoggerConfig` struct.\nThis design is already used in Trace API for getting tracers\nand in Metrics API for getting meters.\n\nRejected alternative:\n\n- [Passing struct as parameter to LoggerProvider.Logger](#passing-struct-as-parameter-to-loggerproviderlogger).\n\n### Logger\n\nThe [`Logger` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#logger)\nis defined as `Logger` interface in [logger.go](logger.go).\n\nThe specification may add new operations to `Logger`.\nThe interface may have methods added without a package major version bump.\nThis embeds `embedded.Logger` to help inform an API implementation\nauthor about this non-standard API evolution.\nThis approach is already used in Trace API and Metrics API.\n\n### Logger.Emit\n\nThe `Emit` method implements the [`Emit a LogRecord` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord).\n\n[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)\nis accepted as a `context.Context` method argument.\n\nCalls to `Emit` are supposed to be on the hot path.\nTherefore, in order to reduce the number of heap allocations,\nthe [`LogRecord` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord),\nis defined as `Record` struct  in [record.go](record.go).\n\n[`Timestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-timestamp)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Timestamp() time.Time\nfunc (r *Record) SetTimestamp(t time.Time)\n```\n\n[`ObservedTimestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-observedtimestamp)\nis accessed using following methods:\n\n```go\nfunc (r *Record) ObservedTimestamp() time.Time\nfunc (r *Record) SetObservedTimestamp(t time.Time)\n```\n\n[`EventName`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-eventname)\nis accessed using following methods:\n\n```go\nfunc (r *Record) EventName() string\nfunc (r *Record) SetEventName(s string)\n```\n\n[`SeverityNumber`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Severity() Severity\nfunc (r *Record) SetSeverity(s Severity)\n```\n\n`Severity` type is defined in [severity.go](severity.go).\nThe constants are are based on\n[Displaying Severity recommendation](https://opentelemetry.io/docs/specs/otel/logs/data-model/#displaying-severity).\nAdditionally, `Severity[Level]` constants are defined to make the API more readable and user friendly.\n\n[`SeverityText`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext)\nis accessed using following methods:\n\n```go\nfunc (r *Record) SeverityText() string\nfunc (r *Record) SetSeverityText(s string)\n```\n\n[`Body`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Body() attribute.Value\nfunc (r *Record) SetBody(v attribute.Value)\n```\n\n[Log record attributes](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-attributes)\nare accessed using following methods:\n\n```go\nfunc (r *Record) WalkAttributes(f func(attribute.KeyValue) bool)\nfunc (r *Record) AddAttributes(attrs ...attribute.KeyValue)\n```\n\n`Record` has a `AttributesLen` method that returns\nthe number of attributes to allow slice preallocation\nwhen converting records to a different representation:\n\n```go\nfunc (r *Record) AttributesLen() int\n```\n\nThe records attributes design and implementation is based on\n[`slog.Record`](https://pkg.go.dev/log/slog#Record).\nIt allows achieving high-performance access and manipulation of the attributes\nwhile keeping the API user friendly.\nIt relieves the user from making his own improvements\nfor reducing the number of allocations when passing attributes.\n\nLog body and attributes use the common\n[`attribute.Value`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#Value)\nand\n[`attribute.KeyValue`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#KeyValue)\ntypes.\nThese types cover the Logs Data Model `any` value shape, including empty\nvalues, byte slices, generic slices, and maps.\nReusing the attribute package keeps the API consistent across signals and\navoids maintaining a second value model with conversion helpers.\n\nThe zero value of `attribute.Value` represents an empty body.\nLog maps use `attribute.MAP`, which may contain duplicate keys when callers\nconstruct one that way. Duplicate-key normalization is an SDK policy, not an\nAPI behavior.\n\nThe caller must not subsequently mutate the record passed to `Emit`.\nThis would allow the implementation to not clone the record,\nbut simply retain, modify or discard it.\nThe implementation may still choose to clone the record or copy its attributes\nif it needs to retain or modify it,\ne.g. in case of asynchronous processing to eliminate the possibility of data races,\nbecause the user can technically reuse the record and add new attributes\nafter the call (even when the documentation says that the caller must not do it).\n\nImplementation requirements:\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements)\n  the method to be safe to be called concurrently.\n\n- The method must not interrupt the record processing if the context is canceled\n  per [\"ignoring context cancellation\" guideline](../CONTRIBUTING.md#ignoring-context-cancellation).\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord)\n  use the current time as observed timestamp if the passed is empty.\n\n- The method should handle the trace context passed via `ctx` argument in order to meet the\n  [specification's SDK requirement](https://opentelemetry.io/docs/specs/otel/logs/sdk/#readablelogrecord)\n  to populate the trace context fields from the resolved context.\n\n`Emit` can be extended by adding new exported fields to the `Record` struct.\n\nRejected alternatives:\n\n- [Record as interface](#record-as-interface)\n- [Options as parameter to Logger.Emit](#options-as-parameter-to-loggeremit)\n- [Passing record as pointer to Logger.Emit](#passing-record-as-pointer-to-loggeremit)\n- [Logger.WithAttributes](#loggerwithattributes)\n- [Record attributes as slice](#record-attributes-as-slice)\n- [Use any instead of attribute.Value](#use-any-instead-of-attributevalue)\n- [Severity type encapsulating number and text](#severity-type-encapsulating-number-and-text)\n- [Define log-specific value types](#define-log-specific-value-types)\n- [Mix receiver types for Record](#mix-receiver-types-for-record)\n- [Add XYZ method to Logger](#add-xyz-method-to-logger)\n\n### Logger.Enabled\n\nThe `Enabled` method implements the [`Enabled` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#enabled).\n\n[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)\nis accepted as a `context.Context` method argument.\n\nCalls to `Enabled` are supposed to be on the hot path and the list of arguments\ncan be extendend in future. Therefore, in order to reduce the number of heap\nallocations and make it possible to handle new arguments, `Enabled` accepts\na `EnabledParameters` struct, defined in [logger.go](logger.go), as the second\nmethod argument.\n\nThe `EnabledParameters` uses fields, instead of getters and setters, to allow\nsimpler usage which allows configuring the `EnabledParameters` in the same line\nwhere `Enabled` is called.\n\n### noop package\n\nThe `go.opentelemetry.io/otel/log/noop` package provides\n[Logs API No-Op Implementation](https://opentelemetry.io/docs/specs/otel/logs/noop/).\n\n### Trace context correlation\n\nThe bridge implementation should do its best to pass\nthe `ctx` containing the trace context from the caller\nso it can later be passed via `Logger.Emit`.\n\nIt is not expected that users (caller or bridge implementation) reconstruct\na `context.Context`. Reconstructing a `context.Context` with\n[`trace.ContextWithSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#ContextWithSpanContext)\nand [`trace.NewSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#NewSpanContext)\nwould usually involve more memory allocations.\n\nThe logging libraries which have recording methods that accepts `context.Context`,\nsuch us [`slog`](https://pkg.go.dev/log/slog),\n[`logrus`](https://pkg.go.dev/github.com/sirupsen/logrus),\n[`zerolog`](https://pkg.go.dev/github.com/rs/zerolog),\nmakes passing the trace context trivial.\n\nHowever, some libraries do not accept a `context.Context` in their recording methods.\nStructured logging libraries,\nsuch as [`logr`](https://pkg.go.dev/github.com/go-logr/logr)\nand [`zap`](https://pkg.go.dev/go.uber.org/zap),\noffer passing `any` type as a log attribute/field.\nTherefore, their bridge implementations can define a \"special\" log attributes/field\nthat will be used to capture the trace context.\n\n[The prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725)\nhas bridge implementations that handle trace context correlation efficiently.\n\n## Benchmarking\n\nThe benchmarks take inspiration from [`slog`](https://pkg.go.dev/log/slog),\nbecause for the Go team it was also critical to create API that would be fast\nand interoperable with existing logging packages.[^2][^3]\n\nThe benchmark results can be found in [the prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725).\n\n## Rejected alternatives\n\n### Reuse slog\n\nThe API must not be coupled to [`slog`](https://pkg.go.dev/log/slog),\nnor any other logging library.\n\nThe API needs to evolve orthogonally to `slog`.\n\n`slog` is not compliant with the [Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/).\nand we cannot expect the Go team to make `slog` compliant with it.\n\nThe interoperability can be achieved using [a log bridge](https://opentelemetry.io/docs/specs/otel/glossary/#log-appender--bridge).\n\nYou can read more about OpenTelemetry Logs design on [opentelemetry.io](https://opentelemetry.io/docs/concepts/signals/logs/).\n\n### Record as interface\n\n`Record` is defined as a `struct` because of the following reasons.\n\nLog record is a value object without any behavior.\nIt is used as data input for Logger methods.\n\nThe log record resembles the instrument config structs like [metric.Float64CounterConfig](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Float64CounterConfig).\n\nUsing `struct` instead of `interface` improves the performance as e.g.\nindirect calls are less optimized,\nusage of interfaces tend to increase heap allocations.[^3]\n\n### Options as parameter to Logger.Emit\n\nOne of the initial ideas was to have:\n\n```go\ntype Logger interface{\n\tembedded.Logger\n\tEmit(ctx context.Context, options ...RecordOption)\n}\n```\n\nThe main reason was that design would be similar\nto the [Meter API](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Meter)\nfor creating instruments.\n\nHowever, passing `Record` directly, instead of using options,\nis more performant as it reduces heap allocations.[^4]\n\nAnother advantage of passing `Record` is that API would not have functions like `NewRecord(options...)`,\nwhich would be used by the SDK and not by the users.\n\nFinally, the definition would be similar to [`slog.Handler.Handle`](https://pkg.go.dev/log/slog#Handler)\nthat was designed to provide optimization opportunities.[^2]\n\n### Passing record as pointer to Logger.Emit\n\nSo far the benchmarks do not show differences that would\nfavor passing the record via pointer (and vice versa).\n\nPassing via value feels safer because of the following reasons.\n\nThe user would not be able to pass `nil`.\nTherefore, it reduces the possibility to have a nil pointer dereference.\n\nIt should reduce the possibility of a heap allocation.\n\nIt follows the design of [`slog.Handler`](https://pkg.go.dev/log/slog#Handler).\n\nIf follows one of Google's Go Style Decisions\nto prefer [passing values](https://google.github.io/styleguide/go/decisions#pass-values).\n\n### Passing struct as parameter to LoggerProvider.Logger\n\nSimilarly to `Logger.Emit`, we could have something like:\n\n```go\ntype LoggerProvider interface{\n\tembedded.LoggerProvider\n\tLogger(name string, config LoggerConfig)\n}\n```\n\nThe drawback of this idea would be that this would be\na different design from Trace and Metrics API.\n\nThe performance of acquiring a logger is not as critical\nas the performance of emitting a log record. While a single\nHTTP/RPC handler could write hundreds of logs, it should not\ncreate a new logger for each log entry.\nThe bridge implementation should reuse loggers whenever possible.\n\n### Logger.WithAttributes\n\nWe could add `WithAttributes` to the `Logger` interface.\nThen `Record` could be a simple struct with only exported fields.\nThe idea was that the SDK would implement the performance improvements\ninstead of doing it in the API.\nThis would allow having different optimization strategies.\n\nDuring the analysis[^5], it occurred that the main problem of this proposal\nis that the variadic slice passed to an interface method is always heap allocated.\n\nMoreover, the logger returned by `WithAttribute` was allocated on the heap.\n\nLastly, the proposal was not specification compliant.\n\n### Record attributes as slice\n\nOne of the proposals[^6] was to have `Record` as a simple struct:\n\n```go\ntype Record struct {\n\tTimestamp         time.Time\n\tObservedTimestamp time.Time\n\tEventName         string\n\tSeverity          Severity\n\tSeverityText      string\n\tBody              Value\n\tAttributes        []KeyValue\n}\n```\n\nThe bridge implementations could use [`sync.Pool`](https://pkg.go.dev/sync#Pool)\nfor reducing the number of allocations when passing attributes.\n\nThe benchmarks results were better.\n\nIn such a design, most bridges would have a `sync.Pool`\nto reduce the number of heap allocations.\nHowever, the `sync.Pool` will not work correctly with API implementations\nthat would take ownership of the record\n(e.g. implementations that do not copy records for asynchronous processing).\nThe current design, even in case of improper API implementation,\nhas lower  chances of encountering a bug as most bridges would\ncreate a record, pass it, and forget about it.\n\nFor reference, here is the reason why `slog` does not use `sync.Pool`[^3]\nas well:\n\n> We can use a sync pool for records though we decided not to.\nYou can but it's a bad idea for us. Why?\nBecause users have control of Records.\nHandler writers can get their hands on a record\nand we'd have to ask them to free it\nor try to free it magically at some some point.\nBut either way, they could get themselves in trouble by freeing it twice\nor holding on to one after they free it.\nThat's a use after free bug and that's why `zerolog` was problematic for us.\n`zerolog` as as part of its speed exposes a pool allocated value to users\nif you use `zerolog` the normal way, that you'll see in all the examples,\nyou will never encounter a problem.\nBut if you do something a little out of the ordinary you can get\nuse after free bugs and we just didn't want to put that in the standard library.\n\nTherefore, we decided to not follow the proposal as it is\nless user friendly (users and bridges would use e.g. a `sync.Pool` to reduce\nthe number of heap allocation), less safe (more prone to use after free bugs\nand race conditions), and the benchmark differences were not significant.\n\n### Use any instead of attribute.Value\n\n[Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)\ndefines Body to be `any`.\nOne could propose to define `Body` (and attribute values) as `any`\ninstead of using `attribute.Value`.\n\nFirst of all, [`any` type defined in the specification](https://opentelemetry.io/docs/specs/otel/logs/data-model/#type-any)\nis not the same as `any` (`interface{}`) in Go.\n\nMoreover, using `any` as a field would decrease the performance.[^7]\n\nUsing `attribute.Value` preserves a typed, allocation-conscious representation\nof the Logs Data Model `any` values while avoiding unconstrained `interface{}`\nhandling in bridge implementations.\n\n### Severity type encapsulating number and text\n\nWe could combine severity into a single field defining a type:\n\n```go\ntype Severity struct {\n\tNumber SeverityNumber\n\tText string\n}\n```\n\nHowever, the [Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#log-and-event-record-definition)\ndefine it as independent fields.\nIt should be more user friendly to have them separated.\nEspecially when having getter and setter methods, setting one value\nwhen the other is already set would be unpleasant.\n\n### Define log-specific value types\n\nThe original design defined `Kind`, `Value`, and `KeyValue` in\n`go.opentelemetry.io/otel/log`.\nThat avoided coupling log bodies to the common attribute package while logs were\nstill exploring structured value support.\n\nThe Logs Data Model and common attribute value model now share the structured\n`any` shapes needed by Go: empty, bool, int64, float64, string, byte slice,\nhomogeneous slices, generic slices, and maps.\nThe specification direction is to reuse these value shapes across signals.\nKeeping log-specific types would duplicate API surface, require conversion\nhelpers, and make bridge code choose between two equivalent value models.\n\nTherefore log records now use `attribute.Value` for body values and\n`attribute.KeyValue` for attributes and map entries.\n\n### Mix receiver types for Record\n\nMethods of [`slog.Record`](https://pkg.go.dev/log/slog#Record)\nhave different receiver types.\n\nIn `log/slog` GitHub issue we can only find that the reason is:[^8]\n\n>> some receiver of Record struct is by value\n> Passing Records by value means they incur no heap allocation.\n> That improves performance overall, even though they are copied.\n\nHowever, the benchmarks do not show any noticeable differences.[^9]\n\nThe compiler is smart-enough to not make a heap allocation for any of these methods.\nThe use of a pointer receiver does not cause any heap allocation.\nFrom Go FAQ:[^10]\n\n> In the current compilers, if a variable has its address taken,\n> that variable is a candidate for allocation on the heap.\n> However, a basic escape analysis recognizes some cases\n> when such variables will not live past the return from the function\n> and can reside on the stack.\n\nThe [Understanding Allocations: the Stack and the Heap](https://www.youtube.com/watch?v=ZMZpH4yT7M0)\npresentation by Jacob Walker describes the escape analysis with details.\n\nMoreover, also from Go FAQ:[^10]\n\n> Also, if a local variable is very large,\n> it might make more sense to store it on the heap rather than the stack.\n\nTherefore, even if we use a value receiver and the value is very large\nit may be heap allocated.\n\nBoth [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments#receiver-type)\nand [Google's Go Style Decisions](https://google.github.io/styleguide/go/decisions#receiver-type)\nhighly recommend making the methods for a type either all pointer methods\nor all value methods. Google's Go Style Decisions even goes further and says:\n\n> There is a lot of misinformation about whether passing a value or a pointer\n> to a function can affect performance.\n> The compiler can choose to pass pointers to values on the stack\n> as well as copying values on the stack,\n> but these considerations should not outweigh the readability\n> and correctness of the code in most circumstances.\n> When the performance does matter, it is important to profile both approaches\n> with a realistic benchmark before deciding that one approach outperforms the other.\n\nBecause, the benchmarks[^9] do not proof any performance difference\nand the general recommendation is to not mix receiver types,\nwe decided to use pointer receivers for all `Record` methods.\n\n### Add XYZ method to Logger\n\nThe `Logger` does not have methods like `SetSeverity`, etc.\nas the Logs API needs to follow (be compliant with)\nthe [specification](https://opentelemetry.io/docs/specs/otel/logs/api/)\n\n[^1]: [Handle structured body and attributes](https://github.com/pellared/opentelemetry-go/pull/7)\n[^2]: Jonathan Amsterdam, [The Go Blog: Structured Logging with slog](https://go.dev/blog/slog)\n[^3]: Jonathan Amsterdam, [GopherCon Europe 2023: A Fast Structured Logging Package](https://www.youtube.com/watch?v=tC4Jt3i62ns)\n[^4]: [Emit definition discussion with benchmarks](https://github.com/open-telemetry/opentelemetry-go/pull/4725#discussion_r1400869566)\n[^5]: [Logger.WithAttributes analysis](https://github.com/pellared/opentelemetry-go/pull/3)\n[^6]: [Record attributes as field and use sync.Pool for reducing allocations](https://github.com/pellared/opentelemetry-go/pull/4) and [Record attributes based on slog.Record](https://github.com/pellared/opentelemetry-go/pull/6)\n[^7]: [Record.Body as any](https://github.com/pellared/opentelemetry-go/pull/5)\n[^8]: [log/slog: structured, leveled logging](https://github.com/golang/go/issues/56345#issuecomment-1302563756)\n[^9]: [Record with pointer receivers only](https://github.com/pellared/opentelemetry-go/pull/8)\n[^10]: [Go FAQ: Stack or heap](https://go.dev/doc/faq#stack_or_heap)\n","isInternal":false,"tokens":5314,"sizeBytes":23515},{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","rawUrl":"https://raw.githubusercontent.com/open-telemetry/opentelemetry-go/HEAD/.github/copilot-instructions.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"# Copilot instructions for opentelemetry-go\n\nThis repository is the Go implementation of OpenTelemetry. Prefer changes that preserve specification compliance, API stability, and idiomatic Go over clever abstractions or broad refactors.\n\n## Implementation rules\n\n- Read the package you are editing and follow its existing patterns for naming, options, error handling, comments, and tests.\n- Keep public APIs backward compatible unless the task explicitly requires a breaking change.\n- Follow the OpenTelemetry specification and semantic conventions. Match span, metric, log, attribute, event, resource, and instrumentation scope behavior to the spec and existing package behavior.\n- Prefer idiomatic Go and the repository's established patterns over inventing new abstractions.\n- Prefer minimal, surgical changes. Avoid requesting speculative flexibility, broad refactors, or unrelated cleanup when the diff can stay focused on the goal.\n- Prefer designs that keep telemetry easy to use and loosely coupled. Choose sensible defaults, avoid vendor-specific APIs or behavior, and do not force unrelated components to depend on each other.\n- For configurable constructors, reuse the project's usual option pattern: unexported `config` types, sealed `Option` interfaces with `apply`, and exported `With...` or `Without...` helpers.\n- Be conservative on hot paths. Avoid unnecessary allocations, reflection, interface churn, blocking, global state, and high-cardinality telemetry.\n- Preserve resilience and concurrency safety. Telemetry must not unexpectedly interfere with the host application; make lifecycle, synchronization, and failure-mode invariants explicit in code and tests.\n- Write comments only for intent, invariants, and non-obvious constraints. Do not add comments that restate the code.\n- Add or update tests for every behavior change. Add or update benchmarks for performance-sensitive changes.\n- Follow [CONTRIBUTING.md Design Choices](../CONTRIBUTING.md#design-choices).\n\n## Documentation and repository conventions\n\n- Non-internal, non-test packages should have Go doc comments, usually in `doc.go`.\n- Non-internal, non-test, non-documentation packages should also have a `README.md` with at least a title and `pkg.go.dev` badge.\n- If a change is user-visible, consider whether `CHANGELOG.md`, examples, package docs, or migration notes also need updates.\n","isInternal":false,"tokens":464,"sizeBytes":2370}],"systemPromptSnippet":"<yakaai_skills repo=\"open-telemetry/opentelemetry-go\">\n<!-- File: AGENTS.md (Tokens: ~1408 | Category: root-instruction) -->\n# Agent Guide for opentelemetry-go\n\nThis file contains active, task-oriented instructions for autonomous and semi-autonomous coding agents working in this repository.\n\nBefore starting any task, read `.github/copilot-instructions.md`, `CONTRIBUTING.md`, and this file.\nTreat `.github/copilot-instructions.md` as global passive guidance for every task, including docs-only and review-only work.\n\n## Core expectations\n\n- Preserve OpenTelemetry specification compliance, API stability, and idiomatic Go.\n- Prefer minimal, surgical changes over broad refactors or speculative cleanup.\n- Read the package you are editing and match its existing naming, option types, error handling, comments, tests, and concurrency patterns.\n- Keep public APIs backward compatible unless the task explicitly requires a breaking change.\n- Keep telemetry resilient and loosely coupled. Do not introduce behavior that can unexpectedly interfere with host applications.\n- Inspect boundaries carefully: input validation, resource limits, cancellation, shutdown, error propagation, concurrency, and memory growth.\n- Prefer fail-safe behavior and explicit invariants over implicit assumptions.\n- Keep dependencies minimal and justified.\n- Preserve host-application safety: telemetry should not panic, block indefinitely, or amplify attacker-controlled input.\n- Be conservative on hot paths. Avoid unnecessary allocations, reflection, interface churn, blocking, global state, and high-cardinality telemetry.\n- Write comments only for intent, invariants, and non-obvious constraints. Do not add comments that restate the code.\n\n## Default workflow\n\nFor new features and behavior changes, use this order unless the task explicitly says otherwise:\n\n1. Read the relevant package, its tests, and any package docs or `README.md`.\n2. Add or update a failing unit test that captures the required behavior or regression.\n3. Implement the smallest change that makes the test pass.\n4. Refactor only after the behavior is locked in, and only if the refactor keeps the diff focused.\n5. If the changed code is on a hot path or performance-sensitive, inspect existing benchmarks and run them. Add a benchmark if coverage is missing.\n6. Update documentation artifacts as needed while the context is fresh. Follow the documentation and changelog conventions below for the specific updates required.\n7. Run `make precommit` each time before considering the work complete.\n\nFor docs-only, test-only, or review-only tasks, still start with the required repository guidance above, then skip the workflow steps that do not apply while keeping the same discipline around scope, verification, and repository conventions.\n\n## Verification\n\n- Use `make` as the canonical repository verification command. The default target is `precommit`.\n- `make precommit` is the expected final verification step for linting, generation, README checks, module checks, and tests.\n- During iteration, targeted commands are fine for fast feedback, but do not stop there if the task changes code.\n- If you touch performance-sensitive code, run focused benchmarks and compare the results using `benchstat` in addition to `make`.\n\n## Documentation and changelog\n\n- Non-internal, non-test packages should have Go doc comments, usually in `doc.go`.\n- Non-internal, non-test, non-documentation packages should also have a `README.md` with at least a title and a `pkg.go.dev` badge.\n- Prefer examples over long code snippets in GoDoc when practical.\n- Keep docs aligned with actual behavior. Do not leave stale comments, stale examples, or stale package documentation behind.\n- For user-visible changes, update `CHANGELOG.md` under the appropriate `Added`, `Changed`, `Deprecated`, `Fixed`, or `Removed` section within `## [Unreleased]`.\n  - Always put the PR number at the end of the line (e.g., `(#1234)`), NOT the issue number.\n  - If the PR number is not yet known, omit it until the PR is created, then update the changelog entry before merging.\n  - Always use references to the go module that is updated (e.g., `go.opentelemetry.io/otel/sdk/metric`), instead of just the path (e.g., `sdk/metric`).\n\n## Repository habits\n\n- Prefer focused diffs. Avoid drive-by cleanup.\n- Follow existing option patterns and exported API conventions instead of inventing new abstractions.\n- Generated files are checked in. If your change affects generation, keep generated output up to date.\n- Prefer fast local search tools such as `rg` when exploring the repository.\n- When changing behavior, make the invariants explicit in tests.\n\n## Personas\n\n### Feature Agent\n\nUse this persona for new behavior, new API surface, or spec-driven feature work.\n\n- Start with a failing unit test.\n- Confirm the expected behavior against the spec, existing package behavior, and public API compatibility.\n- Implement the smallest viable change.\n- Update GoDoc, examples, `README.md`, and `CHANGELOG.md` when the change is user-visible.\n- If the feature touches a hot path, check benchmarks and add one if the coverage is missing.\n\n### Refactoring Agent\n\nUse this persona when improving structure without intentionally changing behavior.\n\n- Treat behavior preservation as the default contract.\n- Add or tighten tests before moving code if current behavior is not already pinned down.\n- Avoid broad rewrites, clever abstractions, or package-wide cleanup unless explicitly requested.\n- If a refactor touches a hot path, benchmark before and after.\n- Keep API shape, semantics, concurrency guarantees, and failure modes unchanged unless the task says otherwise.\n\n### Test Agent\n\nUse this persona when adding missing coverage, reproducing bugs, or hardening regressions.\n\n- Reproduce the bug or missing behavior with the smallest failing test you can.\n- Prefer testing public behavior and externally visible invariants.\n- Add targeted regression tests before changing production code.\n- Only change production code when it is required to make the tested behavior correct or testable.\n- Keep tests deterministic, readable, and aligned with package patterns.\n\n### Performance Agent\n\nUse this persona for hot-path work, allocation reduction, or throughput and latency improvements.\n\n- Benchmark first to establish a baseline.\n- Prefer changes that reduce allocations, copying, interface churn, and unnecessary synchronization.\n- Do not trade away correctness, spec compliance, or API stability for micro-optimizations.\n- Add or update benchmarks when performance-sensitive coverage is missing.\n- If you materially change a hot path, capture before-and-after results, preferably with `benchstat`.\n\n### Review Agent\n\nUse this persona when asked to review code, patches, or pull requests.\n\n- Lead with findings, not summaries.\n- Order findings by severity and include precise file and line references when available.\n- Focus on correctness, spec compliance, API compatibility, concurrency safety, resilience, performance regressions, missing tests, missing benchmarks, documentation gaps, and changelog gaps.\n- Call out when a diff is broader than necessary.\n- If you find no issues, say that explicitly and note any residual risks or verification gaps.\n\n<!-- File: log/DESIGN.md (Tokens: ~5314 | Category: project-spec) -->\n# Logs API\n\n## Abstract\n\n`go.opentelemetry.io/otel/log` provides\n[Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/).\n\nThe prototype was created in\n[#4725](https://github.com/open-telemetry/opentelemetry-go/pull/4725).\n\n## Background\n\nThe key challenge is to create a performant API compliant with the [specification](https://opentelemetry.io/docs/specs/otel/logs/api/)\nwith an intuitive and user friendly design.\nPerformance is seen as one of the most important characteristics of logging libraries in Go.\n\n## Design\n\nThis proposed design aims to:\n\n- be specification compliant,\n- be similar to Trace and Metrics API,\n- take advantage of both OpenTelemetry and `slog` experience to achieve acceptable performance.\n\n### Module structure\n\nThe API is published as a single `go.opentelemetry.io/otel/log` Go module.\n\nThe package structure is similar to Trace API and Metrics API.\nThe Go module consists of the following packages:\n\n- `go.opentelemetry.io/otel/log`\n- `go.opentelemetry.io/otel/log/embedded`\n- `go.opentelemetry.io/otel/log/logtest`\n- `go.opentelemetry.io/otel/log/noop`\n\nRejected alternative:\n\n- [Reuse slog](#reuse-slog)\n\n### LoggerProvider\n\nThe [`LoggerProvider` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#loggerprovider)\nis defined as `LoggerProvider` interface in [provider.go](provider.go).\n\nThe specification may add new operations to `LoggerProvider`.\nThe interface may have methods added without a package major version bump.\nThis embeds `embedded.LoggerProvider` to help inform an API implementation\nauthor about this non-standard API evolution.\nThis approach is already used in Trace API and Metrics API.\n\n#### LoggerProvider.Logger\n\nThe `Logger` method implements the [`Get a Logger` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#get-a-logger).\n\nThe required `name` parameter is accepted as a `string` method argument.\n\nThe `LoggerOption` options are defined to support optional parameters.\n\nImplementation requirements:\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements)\n  the method to be safe to be called concurrently.\n\n- If the passed name is empty, this should be reported as invalid as specified\n  by the [Logs SDK specification](https://opentelemetry.io/docs/specs/otel/logs/sdk/#logger-creation).\n  The method should still use it as the instrumentation scope name and return\n  a working logger.\n\n`Logger` can be extended by adding new `LoggerOption` options\nand adding new exported fields to the `LoggerConfig` struct.\nThis design is already used in Trace API for getting tracers\nand in Metrics API for getting meters.\n\nRejected alternative:\n\n- [Passing struct as parameter to LoggerProvider.Logger](#passing-struct-as-parameter-to-loggerproviderlogger).\n\n### Logger\n\nThe [`Logger` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#logger)\nis defined as `Logger` interface in [logger.go](logger.go).\n\nThe specification may add new operations to `Logger`.\nThe interface may have methods added without a package major version bump.\nThis embeds `embedded.Logger` to help inform an API implementation\nauthor about this non-standard API evolution.\nThis approach is already used in Trace API and Metrics API.\n\n### Logger.Emit\n\nThe `Emit` method implements the [`Emit a LogRecord` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord).\n\n[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)\nis accepted as a `context.Context` method argument.\n\nCalls to `Emit` are supposed to be on the hot path.\nTherefore, in order to reduce the number of heap allocations,\nthe [`LogRecord` abstraction](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord),\nis defined as `Record` struct  in [record.go](record.go).\n\n[`Timestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-timestamp)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Timestamp() time.Time\nfunc (r *Record) SetTimestamp(t time.Time)\n```\n\n[`ObservedTimestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-observedtimestamp)\nis accessed using following methods:\n\n```go\nfunc (r *Record) ObservedTimestamp() time.Time\nfunc (r *Record) SetObservedTimestamp(t time.Time)\n```\n\n[`EventName`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-eventname)\nis accessed using following methods:\n\n```go\nfunc (r *Record) EventName() string\nfunc (r *Record) SetEventName(s string)\n```\n\n[`SeverityNumber`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Severity() Severity\nfunc (r *Record) SetSeverity(s Severity)\n```\n\n`Severity` type is defined in [severity.go](severity.go).\nThe constants are are based on\n[Displaying Severity recommendation](https://opentelemetry.io/docs/specs/otel/logs/data-model/#displaying-severity).\nAdditionally, `Severity[Level]` constants are defined to make the API more readable and user friendly.\n\n[`SeverityText`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext)\nis accessed using following methods:\n\n```go\nfunc (r *Record) SeverityText() string\nfunc (r *Record) SetSeverityText(s string)\n```\n\n[`Body`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)\nis accessed using following methods:\n\n```go\nfunc (r *Record) Body() attribute.Value\nfunc (r *Record) SetBody(v attribute.Value)\n```\n\n[Log record attributes](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-attributes)\nare accessed using following methods:\n\n```go\nfunc (r *Record) WalkAttributes(f func(attribute.KeyValue) bool)\nfunc (r *Record) AddAttributes(attrs ...attribute.KeyValue)\n```\n\n`Record` has a `AttributesLen` method that returns\nthe number of attributes to allow slice preallocation\nwhen converting records to a different representation:\n\n```go\nfunc (r *Record) AttributesLen() int\n```\n\nThe records attributes design and implementation is based on\n[`slog.Record`](https://pkg.go.dev/log/slog#Record).\nIt allows achieving high-performance access and manipulation of the attributes\nwhile keeping the API user friendly.\nIt relieves the user from making his own improvements\nfor reducing the number of allocations when passing attributes.\n\nLog body and attributes use the common\n[`attribute.Value`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#Value)\nand\n[`attribute.KeyValue`](https://pkg.go.dev/go.opentelemetry.io/otel/attribute#KeyValue)\ntypes.\nThese types cover the Logs Data Model `any` value shape, including empty\nvalues, byte slices, generic slices, and maps.\nReusing the attribute package keeps the API consistent across signals and\navoids maintaining a second value model with conversion helpers.\n\nThe zero value of `attribute.Value` represents an empty body.\nLog maps use `attribute.MAP`, which may contain duplicate keys when callers\nconstruct one that way. Duplicate-key normalization is an SDK policy, not an\nAPI behavior.\n\nThe caller must not subsequently mutate the record passed to `Emit`.\nThis would allow the implementation to not clone the record,\nbut simply retain, modify or discard it.\nThe implementation may still choose to clone the record or copy its attributes\nif it needs to retain or modify it,\ne.g. in case of asynchronous processing to eliminate the possibility of data races,\nbecause the user can technically reuse the record and add new attributes\nafter the call (even when the documentation says that the caller must not do it).\n\nImplementation requirements:\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#concurrency-requirements)\n  the method to be safe to be called concurrently.\n\n- The method must not interrupt the record processing if the context is canceled\n  per [\"ignoring context cancellation\" guideline](../CONTRIBUTING.md#ignoring-context-cancellation).\n\n- The [specification requires](https://opentelemetry.io/docs/specs/otel/logs/api/#emit-a-logrecord)\n  use the current time as observed timestamp if the passed is empty.\n\n- The method should handle the trace context passed via `ctx` argument in order to meet the\n  [specification's SDK requirement](https://opentelemetry.io/docs/specs/otel/logs/sdk/#readablelogrecord)\n  to populate the trace context fields from the resolved context.\n\n`Emit` can be extended by adding new exported fields to the `Record` struct.\n\nRejected alternatives:\n\n- [Record as interface](#record-as-interface)\n- [Options as parameter to Logger.Emit](#options-as-parameter-to-loggeremit)\n- [Passing record as pointer to Logger.Emit](#passing-record-as-pointer-to-loggeremit)\n- [Logger.WithAttributes](#loggerwithattributes)\n- [Record attributes as slice](#record-attributes-as-slice)\n- [Use any instead of attribute.Value](#use-any-instead-of-attributevalue)\n- [Severity type encapsulating number and text](#severity-type-encapsulating-number-and-text)\n- [Define log-specific value types](#define-log-specific-value-types)\n- [Mix receiver types for Record](#mix-receiver-types-for-record)\n- [Add XYZ method to Logger](#add-xyz-method-to-logger)\n\n### Logger.Enabled\n\nThe `Enabled` method implements the [`Enabled` operation](https://opentelemetry.io/docs/specs/otel/logs/api/#enabled).\n\n[`Context` associated with the `LogRecord`](https://opentelemetry.io/docs/specs/otel/context/)\nis accepted as a `context.Context` method argument.\n\nCalls to `Enabled` are supposed to be on the hot path and the list of arguments\ncan be extendend in future. Therefore, in order to reduce the number of heap\nallocations and make it possible to handle new arguments, `Enabled` accepts\na `EnabledParameters` struct, defined in [logger.go](logger.go), as the second\nmethod argument.\n\nThe `EnabledParameters` uses fields, instead of getters and setters, to allow\nsimpler usage which allows configuring the `EnabledParameters` in the same line\nwhere `Enabled` is called.\n\n### noop package\n\nThe `go.opentelemetry.io/otel/log/noop` package provides\n[Logs API No-Op Implementation](https://opentelemetry.io/docs/specs/otel/logs/noop/).\n\n### Trace context correlation\n\nThe bridge implementation should do its best to pass\nthe `ctx` containing the trace context from the caller\nso it can later be passed via `Logger.Emit`.\n\nIt is not expected that users (caller or bridge implementation) reconstruct\na `context.Context`. Reconstructing a `context.Context` with\n[`trace.ContextWithSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#ContextWithSpanContext)\nand [`trace.NewSpanContext`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#NewSpanContext)\nwould usually involve more memory allocations.\n\nThe logging libraries which have recording methods that accepts `context.Context`,\nsuch us [`slog`](https://pkg.go.dev/log/slog),\n[`logrus`](https://pkg.go.dev/github.com/sirupsen/logrus),\n[`zerolog`](https://pkg.go.dev/github.com/rs/zerolog),\nmakes passing the trace context trivial.\n\nHowever, some libraries do not accept a `context.Context` in their recording methods.\nStructured logging libraries,\nsuch as [`logr`](https://pkg.go.dev/github.com/go-logr/logr)\nand [`zap`](https://pkg.go.dev/go.uber.org/zap),\noffer passing `any` type as a log attribute/field.\nTherefore, their bridge implementations can define a \"special\" log attributes/field\nthat will be used to capture the trace context.\n\n[The prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725)\nhas bridge implementations that handle trace context correlation efficiently.\n\n## Benchmarking\n\nThe benchmarks take inspiration from [`slog`](https://pkg.go.dev/log/slog),\nbecause for the Go team it was also critical to create API that would be fast\nand interoperable with existing logging packages.[^2][^3]\n\nThe benchmark results can be found in [the prototype](https://github.com/open-telemetry/opentelemetry-go/pull/4725).\n\n## Rejected alternatives\n\n### Reuse slog\n\nThe API must not be coupled to [`slog`](https://pkg.go.dev/log/slog),\nnor any other logging library.\n\nThe API needs to evolve orthogonally to `slog`.\n\n`slog` is not compliant with the [Logs API](https://opentelemetry.io/docs/specs/otel/logs/api/).\nand we cannot expect the Go team to make `slog` compliant with it.\n\nThe interoperability can be achieved using [a log bridge](https://opentelemetry.io/docs/specs/otel/glossary/#log-appender--bridge).\n\nYou can read more about OpenTelemetry Logs design on [opentelemetry.io](https://opentelemetry.io/docs/concepts/signals/logs/).\n\n### Record as interface\n\n`Record` is defined as a `struct` because of the following reasons.\n\nLog record is a value object without any behavior.\nIt is used as data input for Logger methods.\n\nThe log record resembles the instrument config structs like [metric.Float64CounterConfig](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Float64CounterConfig).\n\nUsing `struct` instead of `interface` improves the performance as e.g.\nindirect calls are less optimized,\nusage of interfaces tend to increase heap allocations.[^3]\n\n### Options as parameter to Logger.Emit\n\nOne of the initial ideas was to have:\n\n```go\ntype Logger interface{\n\tembedded.Logger\n\tEmit(ctx context.Context, options ...RecordOption)\n}\n```\n\nThe main reason was that design would be similar\nto the [Meter API](https://pkg.go.dev/go.opentelemetry.io/otel/metric#Meter)\nfor creating instruments.\n\nHowever, passing `Record` directly, instead of using options,\nis more performant as it reduces heap allocations.[^4]\n\nAnother advantage of passing `Record` is that API would not have functions like `NewRecord(options...)`,\nwhich would be used by the SDK and not by the users.\n\nFinally, the definition would be similar to [`slog.Handler.Handle`](https://pkg.go.dev/log/slog#Handler)\nthat was designed to provide optimization opportunities.[^2]\n\n### Passing record as pointer to Logger.Emit\n\nSo far the benchmarks do not show differences that would\nfavor passing the record via pointer (and vice versa).\n\nPassing via value feels safer because of the following reasons.\n\nThe user would not be able to pass `nil`.\nTherefore, it reduces the possibility to have a nil pointer dereference.\n\nIt should reduce the possibility of a heap allocation.\n\nIt follows the design of [`slog.Handler`](https://pkg.go.dev/log/slog#Handler).\n\nIf follows one of Google's Go Style Decisions\nto prefer [passing values](https://google.github.io/styleguide/go/decisions#pass-values).\n\n### Passing struct as parameter to LoggerProvider.Logger\n\nSimilarly to `Logger.Emit`, we could have something like:\n\n```go\ntype LoggerProvider interface{\n\tembedded.LoggerProvider\n\tLogger(name string, config LoggerConfig)\n}\n```\n\nThe drawback of this idea would be that this would be\na different design from Trace and Metrics API.\n\nThe performance of acquiring a logger is not as critical\nas the performance of emitting a log record. While a single\nHTTP/RPC handler could write hundreds of logs, it should not\ncreate a new logger for each log entry.\nThe bridge implementation should reuse loggers whenever possible.\n\n### Logger.WithAttributes\n\nWe could add `WithAttributes` to the `Logger` interface.\nThen `Record` could be a simple struct with only exported fields.\nThe idea was that the SDK would implement the performance improvements\ninstead of doing it in the API.\nThis would allow having different optimization strategies.\n\nDuring the analysis[^5], it occurred that the main problem of this proposal\nis that the variadic slice passed to an interface method is always heap allocated.\n\nMoreover, the logger returned by `WithAttribute` was allocated on the heap.\n\nLastly, the proposal was not specification compliant.\n\n### Record attributes as slice\n\nOne of the proposals[^6] was to have `Record` as a simple struct:\n\n```go\ntype Record struct {\n\tTimestamp         time.Time\n\tObservedTimestamp time.Time\n\tEventName         string\n\tSeverity          Severity\n\tSeverityText      string\n\tBody              Value\n\tAttributes        []KeyValue\n}\n```\n\nThe bridge implementations could use [`sync.Pool`](https://pkg.go.dev/sync#Pool)\nfor reducing the number of allocations when passing attributes.\n\nThe benchmarks results were better.\n\nIn such a design, most bridges would have a `sync.Pool`\nto reduce the number of heap allocations.\nHowever, the `sync.Pool` will not work correctly with API implementations\nthat would take ownership of the record\n(e.g. implementations that do not copy records for asynchronous processing).\nThe current design, even in case of improper API implementation,\nhas lower  chances of encountering a bug as most bridges would\ncreate a record, pass it, and forget about it.\n\nFor reference, here is the reason why `slog` does not use `sync.Pool`[^3]\nas well:\n\n> We can use a sync pool for records though we decided not to.\nYou can but it's a bad idea for us. Why?\nBecause users have control of Records.\nHandler writers can get their hands on a record\nand we'd have to ask them to free it\nor try to free it magically at some some point.\nBut either way, they could get themselves in trouble by freeing it twice\nor holding on to one after they free it.\nThat's a use after free bug and that's why `zerolog` was problematic for us.\n`zerolog` as as part of its speed exposes a pool allocated value to users\nif you use `zerolog` the normal way, that you'll see in all the examples,\nyou will never encounter a problem.\nBut if you do something a little out of the ordinary you can get\nuse after free bugs and we just didn't want to put that in the standard library.\n\nTherefore, we decided to not follow the proposal as it is\nless user friendly (users and bridges would use e.g. a `sync.Pool` to reduce\nthe number of heap allocation), less safe (more prone to use after free bugs\nand race conditions), and the benchmark differences were not significant.\n\n### Use any instead of attribute.Value\n\n[Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)\ndefines Body to be `any`.\nOne could propose to define `Body` (and attribute values) as `any`\ninstead of using `attribute.Value`.\n\nFirst of all, [`any` type defined in the specification](https://opentelemetry.io/docs/specs/otel/logs/data-model/#type-any)\nis not the same as `any` (`interface{}`) in Go.\n\nMoreover, using `any` as a field would decrease the performance.[^7]\n\nUsing `attribute.Value` preserves a typed, allocation-conscious representation\nof the Logs Data Model `any` values while avoiding unconstrained `interface{}`\nhandling in bridge implementations.\n\n### Severity type encapsulating number and text\n\nWe could combine severity into a single field defining a type:\n\n```go\ntype Severity struct {\n\tNumber SeverityNumber\n\tText string\n}\n```\n\nHowever, the [Logs Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/#log-and-event-record-definition)\ndefine it as independent fields.\nIt should be more user friendly to have them separated.\nEspecially when having getter and setter methods, setting one value\nwhen the other is already set would be unpleasant.\n\n### Define log-specific value types\n\nThe original design defined `Kind`, `Value`, and `KeyValue` in\n`go.opentelemetry.io/otel/log`.\nThat avoided coupling log bodies to the common attribute package while logs were\nstill exploring structured value support.\n\nThe Logs Data Model and common attribute value model now share the structured\n`any` shapes needed by Go: empty, bool, int64, float64, string, byte slice,\nhomogeneous slices, generic slices, and maps.\nThe specification direction is to reuse these value shapes across signals.\nKeeping log-specific types would duplicate API surface, require conversion\nhelpers, and make bridge code choose between two equivalent value models.\n\nTherefore log records now use `attribute.Value` for body values and\n`attribute.KeyValue` for attributes and map entries.\n\n### Mix receiver types for Record\n\nMethods of [`slog.Record`](https://pkg.go.dev/log/slog#Record)\nhave different receiver types.\n\nIn `log/slog` GitHub issue we can only find that the reason is:[^8]\n\n>> some receiver of Record struct is by value\n> Passing Records by value means they incur no heap allocation.\n> That improves performance overall, even though they are copied.\n\nHowever, the benchmarks do not show any noticeable differences.[^9]\n\nThe compiler is smart-enough to not make a heap allocation for any of these methods.\nThe use of a pointer receiver does not cause any heap allocation.\nFrom Go FAQ:[^10]\n\n> In the current compilers, if a variable has its address taken,\n> that variable is a candidate for allocation on the heap.\n> However, a basic escape analysis recognizes some cases\n> when such variables will not live past the return from the function\n> and can reside on the stack.\n\nThe [Understanding Allocations: the Stack and the Heap](https://www.youtube.com/watch?v=ZMZpH4yT7M0)\npresentation by Jacob Walker describes the escape analysis with details.\n\nMoreover, also from Go FAQ:[^10]\n\n> Also, if a local variable is very large,\n> it might make more sense to store it on the heap rather than the stack.\n\nTherefore, even if we use a value receiver and the value is very large\nit may be heap allocated.\n\nBoth [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments#receiver-type)\nand [Google's Go Style Decisions](https://google.github.io/styleguide/go/decisions#receiver-type)\nhighly recommend making the methods for a type either all pointer methods\nor all value methods. Google's Go Style Decisions even goes further and says:\n\n> There is a lot of misinformation about whether passing a value or a pointer\n> to a function can affect performance.\n> The compiler can choose to pass pointers to values on the stack\n> as well as copying values on the stack,\n> but these considerations should not outweigh the readability\n> and correctness of the code in most circumstances.\n> When the performance does matter, it is important to profile both approaches\n> with a realistic benchmark before deciding that one approach outperforms the other.\n\nBecause, the benchmarks[^9] do not proof any performance difference\nand the general recommendation is to not mix receiver types,\nwe decided to use pointer receivers for all `Record` methods.\n\n### Add XYZ method to Logger\n\nThe `Logger` does not have methods like `SetSeverity`, etc.\nas the Logs API needs to follow (be compliant with)\nthe [specification](https://opentelemetry.io/docs/specs/otel/logs/api/)\n\n[^1]: [Handle structured body and attributes](https://github.com/pellared/opentelemetry-go/pull/7)\n[^2]: Jonathan Amsterdam, [The Go Blog: Structured Logging with slog](https://go.dev/blog/slog)\n[^3]: Jonathan Amsterdam, [GopherCon Europe 2023: A Fast Structured Logging Package](https://www.youtube.com/watch?v=tC4Jt3i62ns)\n[^4]: [Emit definition discussion with benchmarks](https://github.com/open-telemetry/opentelemetry-go/pull/4725#discussion_r1400869566)\n[^5]: [Logger.WithAttributes analysis](https://github.com/pellared/opentelemetry-go/pull/3)\n[^6]: [Record attributes as field and use sync.Pool for reducing allocations](https://github.com/pellared/opentelemetry-go/pull/4) and [Record attributes based on slog.Record](https://github.com/pellared/opentelemetry-go/pull/6)\n[^7]: [Record.Body as any](https://github.com/pellared/opentelemetry-go/pull/5)\n[^8]: [log/slog: structured, leveled logging](https://github.com/golang/go/issues/56345#issuecomment-1302563756)\n[^9]: [Record with pointer receivers only](https://github.com/pellared/opentelemetry-go/pull/8)\n[^10]: [Go FAQ: Stack or heap](https://go.dev/doc/faq#stack_or_heap)\n\n<!-- File: .github/copilot-instructions.md (Tokens: ~464 | Category: copilot-instructions) -->\n# Copilot instructions for opentelemetry-go\n\nThis repository is the Go implementation of OpenTelemetry. Prefer changes that preserve specification compliance, API stability, and idiomatic Go over clever abstractions or broad refactors.\n\n## Implementation rules\n\n- Read the package you are editing and follow its existing patterns for naming, options, error handling, comments, and tests.\n- Keep public APIs backward compatible unless the task explicitly requires a breaking change.\n- Follow the OpenTelemetry specification and semantic conventions. Match span, metric, log, attribute, event, resource, and instrumentation scope behavior to the spec and existing package behavior.\n- Prefer idiomatic Go and the repository's established patterns over inventing new abstractions.\n- Prefer minimal, surgical changes. Avoid requesting speculative flexibility, broad refactors, or unrelated cleanup when the diff can stay focused on the goal.\n- Prefer designs that keep telemetry easy to use and loosely coupled. Choose sensible defaults, avoid vendor-specific APIs or behavior, and do not force unrelated components to depend on each other.\n- For configurable constructors, reuse the project's usual option pattern: unexported `config` types, sealed `Option` interfaces with `apply`, and exported `With...` or `Without...` helpers.\n- Be conservative on hot paths. Avoid unnecessary allocations, reflection, interface churn, blocking, global state, and high-cardinality telemetry.\n- Preserve resilience and concurrency safety. Telemetry must not unexpectedly interfere with the host application; make lifecycle, synchronization, and failure-mode invariants explicit in code and tests.\n- Write comments only for intent, invariants, and non-obvious constraints. Do not add comments that restate the code.\n- Add or update tests for every behavior change. Add or update benchmarks for performance-sensitive changes.\n- Follow [CONTRIBUTING.md Design Choices](../CONTRIBUTING.md#design-choices).\n\n## Documentation and repository conventions\n\n- Non-internal, non-test packages should have Go doc comments, usually in `doc.go`.\n- Non-internal, non-test, non-documentation packages should also have a `README.md` with at least a title and `pkg.go.dev` badge.\n- If a change is user-visible, consider whether `CHANGELOG.md`, examples, package docs, or migration notes also need updates.\n</yakaai_skills>"}