-
Notifications
You must be signed in to change notification settings - Fork 524
Description
Background
Currently, semantic convention attributes generated for OpenTelemetry C++ SDK only include string constants for attribute names, with type information (e.g., string, string[], int, bool) only present in source YAML or template files. This limits the ability of applications and SDK to perform type-based sanity checks for attributes, especially when setting resource or span attributes according to semantic conventions.
Reference: Java Implementation
The Java API provides type-safe semantic convention attributes using [AttributeKey<T>](https://github.com/open-telemetry/opentelemetry-java/blob/main/api/all/src/main/java/io/opentelemetry/api/common/AttributeKey. java).
This approach:
- Exposes a generic, type-safe key with compile-time checks.
- Supplies factory methods for common types and arrays.
- Enables both compile-time and runtime attribute validation.
Example:
AttributeKey<String> kHostName = AttributeKey.stringKey("host.name");
AttributeKey<List<String>> kHostIp = AttributeKey.stringArrayKey("host.ip");Type-Safe API with Backward Compatibility
Inspired by the Java AttributeKey<T> approach, this proposal introduces a type-safe API for semantic convention attributes, while fully preserving backward compatibility by keeping the existing API unchanged.
Solution: Dual API with Forward-Looking Migration Path
- Keep the current
ResourceAttributesAPI as-is for legacy/backward-compatible usage (planned for eventual deprecation). - Introduce a new type-safe API:
- Add a
TypedResourceAttributesclass that provides a template method for setting attributes using typed keys. - Generate new
AttributeKey<T>definitions for each semantic convention attribute, exposing both the attribute name and the expected type at compile time. - Generate the new keys in a
typedsub-namespace for each semconv group, e.g.,semconv::host::typed::kHostIp.
- Add a
- Update SDK to accept
TypedResourceAttributesdirectly:- Modify
Resource::Create()to accept bothResourceAttributes(legacy) andTypedResourceAttributes(new). - No conversion methods — the new API is the forward path; the old API will eventually be deprecated and removed.
- Modify
- Custom attributes are easy to define:
- Users can define their own typed attribute keys using the same
AttributeKey<T>pattern.
- Users can define their own typed attribute keys using the same
Example
// Legacy usage (unchanged, but deprecated in future)
ResourceAttributes legacy_attrs;
legacy_attrs.SetAttribute(semconv::host::kHostIp, std::vector<std::string>{"192.168.1.1"});
auto resource = Resource::Create(legacy_attrs); // Still works
// NEW: Type-safe usage (forward-looking)
TypedResourceAttributes attrs;
attrs.Set(semconv::host::typed::kHostIp, std::vector<std::string>{"192.168.1.1"});
attrs.Set(semconv:: host::typed::kHostName, "my-server");
// Compile-time error for wrong type:
// attrs.Set(semconv::host::typed::kHostIp, "192.168.1.1"); // Error!
// Direct usage — no conversion needed
auto resource = Resource::Create(attrs); // NEW: Accepts TypedResourceAttributes
// Custom attributes
constexpr auto kMyCustomAttr = AttributeKey<int64_t>("my.custom.metric", AttributeType::kInt64);
attrs.Set(kMyCustomAttr, 12345);Generated Semantic Convention Example
namespace semconv::host {
// Legacy (eventually deprecated)
static constexpr const char* kHostIp = "host.ip";
// NEW: Type-safe keys
namespace typed {
constexpr auto kHostIp = AttributeKey<std::vector<std::string>>("host.ip", AttributeType::kStringArray);
constexpr auto kHostName = AttributeKey<std::string>("host.name", AttributeType::kString);
constexpr auto kHostCpuCacheL2Size = AttributeKey<int64_t>("host.cpu.cache.l2.size", AttributeType::kInt64);
}
}SDK API Update
namespace opentelemetry::sdk::resource {
class Resource {
public:
// Legacy (keep for backward compatibility)
static std::unique_ptr<Resource> Create(const ResourceAttributes& attributes);
// NEW: Forward-looking type-safe API
static std::unique_ptr<Resource> Create(const TypedResourceAttributes& attributes);
};
} // namespaceBenefits
- Backward compatible: All existing code works as-is.
- Compile-time safety: New code cannot set incorrect types for semantic conventions.
- Forward-looking: No conversion methods —
TypedResourceAttributesis the future. - Clear migration path: Developers can incrementally migrate; old API will be deprecated later.
- Easy custom attributes: Users define their own
AttributeKey<T>for custom attributes. - Clear discoverability: New
typednamespace for semantic-convention keys.
Migration Strategy
Phase 1 (v1.x): Introduce TypedResourceAttributes and AttributeKey<T>, update Resource::Create() to accept both.
Phase 2 (v1.x+n): Deprecate ResourceAttributes with warnings.
Phase 3 (v2.0): Remove ResourceAttributes entirely; TypedResourceAttributes becomes the standard.
Request
Is the community supportive of this forward-looking approach (aligning with Java's model)? If so, I am willing to contribute a PoC or PR for code generation, examples, and integration.
Previous alternatives considered:
- Generate attribute type enums per constant (
kHostIpType) - Generate a central registry map at runtime
- Generate metadata structs per attribute
- Conversion methods between old and new APIs (rejected — forward path only)
This proposal prefers a type-safe, Java-like API with a clear forward migration path and eventual removal of the legacy API.