Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to handle common / global attributes? #4274

Closed
1 of 2 tasks
martinkuba opened this issue Nov 9, 2023 · 6 comments
Closed
1 of 2 tasks

How to handle common / global attributes? #4274

martinkuba opened this issue Nov 9, 2023 · 6 comments
Labels
Discussion Issue or PR that needs/is extended discussion. stale

Comments

@martinkuba
Copy link
Contributor

  • This only affects the JavaScript OpenTelemetry library
  • This may affect other libraries, but I would like to get opinions here first

The intent of this issue is to open a discussion about how to implement handling of common/shared attributes. Common attributes are similar to resource attributes in that they apply to all spans and logs, but they are different in that they are mutable.

Background

Client instrumentation has several use cases for attributes that should be associated with all spans and logs generated within a given time period. The primary use case is to represent a session (the session.id attribute has recently been added to semantic conventions), but there are other use cases including:

  • visitor id
  • page impression id
  • page url
  • geo location data
  • network information
  • language preference
  • screen width and height

Compared with Resource attributes

We originally wanted to send these as resource attributes (see this OTEP). However, the challenge with these attributes is that their values can change during the lifetime of the SDK. Therefore, the direction we have received from the TC is to add them to each signal instead.

Compared with Context attributes

A distinction also needs to be made with trace-context attributes, as proposed in this OTEP. Client attributes, like session ID, need to be applied to many traces and standalone events generated by a client application, not just a single trace.

Questions

Should there be a standard mechanism in the SDK to handle these attributes?

Should this be standardized across all SDKs and documented in the specification?

Discussion

The options that I can think of:

Option 1: Each attribute is added by a separate span/log processor

The implementation would be straight-forward. However, adding many attributes means managing many processors: two processors (span and log) for each attribute. This may be difficult to configure and manage.

Setting and retrieving the attribute values could be handled on a case-by-case basis. A processor, for example, could itself include the detection of the value. Or, it could expose methods to set the value from an external code.

Example:

tracerProvider.addSpanProcessor(new SessionIdSpanProcessor());
tracerProvider.addSpanProcessor(new VisitorIdSpanProcessor());
tracerProvider.addSpanProcessor(new GeoLocationSpanProcessor());

loggerProvider.addLogProcessor(new SessionIdLogProcessor());
loggerProvider.addLogProcessor(new VisitorIdLogProcessor());
loggerProvider.addLogProcessor(new GeoLocationLogProcessor());

Option 2: There is a single span/log processor used to add all common attributes

There would be two processors only: one for spans and one for logs. The question is how would attributes be added and updated. The processor could accept a collection of attribute providers, or it could retrieve the attributes from a global attribute store (provided by the SDK). A prototype of the latter is available here.

For the first option, an interface would need to be defined for the attribute providers. These providers would need to be configured and passed to the processor during initialization.

const providers = [
	new SessionIdAttributeProvider(),
	new VisitorIdAttributeProvider()
	new GeoLocationAttributeProvider(),
]

tracerProvider.addSpanProcessor(new GlobalAttributesSpanProcessor(providers));
loggerProvider.addLogProcessor(new GlobalAttributesLogProcessor(providers));

Option 3: The mechanism to add these attributes is built-in to the SDK

With this option, there is no span/log processor. The SDK provides an API to set/update global attributes, and it automatically adds them when a span or log is created.

For example:

tracerProvider.setGlobalAttribute(name, value);
loggerProvider.setGlobalAttribute(name, value);

or perhaps:

new TracerProvicer({
	globalAttributeProviders: [
		new SessionIdAttributeProvider(),
		new VisitorIdAttributeProvider()
		new GeoLocationAttributeProvider(),
	]
})

Existing implementations

The Android SDK currently has a SessionIdSpanAppender span processor that adds the session ID attribute to all spans. It also has the GlobalAttributesSpanAppender span processor that can add multiple attributes at the same time.

We have also implemented a prototype in JavaScript that introduces a GlobalAttributesSpanProcessor and GlobalAttributesLogRecordProcessor
processors. The attributes are retrieved from a global store, which allows for any component to add global attributes.

@martinkuba martinkuba added the Discussion Issue or PR that needs/is extended discussion. label Nov 9, 2023
@Flarna
Copy link
Member

Flarna commented Nov 9, 2023

If this ends up in SDK I would expect it to be similar across techs. If this happens it likely needs to be an optional component/api there because techs are already different in some areas (like automatic context propagation).

Is this only applicable to browsers or also to node.js/deno/...
If only for browsers it should be likely at WebSDK or in web specific instrumentations.
If it is on API level or generic SDK we need to clearly specify how it behaves in non web setups.

Which component is responsible for such global changes?

  • Some blessed instrumentation?
  • Actual application code which did the SDK setup?
  • What about automatic setups in this case where monitoring is "just added"?
  • Is there a specific "owner" of this state?

Is it allowed to have more parallel sessions running?
If yes, how is it ensured that all (mostly independent) instrumentations are aware of this and select the "correct" session?

Is it allowed that spans on the same trace are on different sessions?
Current proposals seem to allow this as span creation is unrelated to global state change and several traces may run when state is changed.

@scheler
Copy link
Contributor

scheler commented Nov 23, 2023

@martinkuba

  1. I suggest skipping option 3 as it touches TracerProvider and will require more discussion / approvals.
  2. Option 2 looks very similar to MultiSpanProcessor in opentelemetry-java, so you can introduce the same in opentelemetry-js too.
  3. I think we don't need the term "Global" in GlobalAttributeProcessor as the processors are global already - that is, they are applied to all the signals emitted by instrumentations configured with tracer provider. We can stop here and implement separate processors for each concern and use the MultiSpanProcessor to configure them all in one place.
  4. Optionally, if the term Processor sounds generic and your intent is to convey that the new interface is to inject an attribute then the interface could take the attribute name to be injected as a parameter, for eg., session.id, and a generator class that generates only a value for this attribute. For eg., AttributeInjector(attributeName, ValueGenerator)

@martinkuba
Copy link
Contributor Author

@scheler:

Option 2 looks very similar to MultiSpanProcessor in opentelemetry-java, so you can introduce the same in opentelemetry-js too.

I agree that it is similar, but there is a subtle difference. The MultiSpanProcessor is more generic; it can take any SpanProcessor and invoke its processing, which could be doing anything. My proposal with the GlobalAttributesSpanProcessor is that this processor adds the attributes - it's a generic attributes "adder". The providers are there only to supply the attributes to be added.

I think we don't need the term "Global" in GlobalAttributeProcessor as the processors are global already

Having "GlobalAttribute" in the name denotes that this processor adds attributes that are considered global. In other words, this just describes what this processor does.

@martinkuba
Copy link
Contributor Author

@Flarna

If only for browsers it should be likely at WebSDK or in web specific instrumentations.

The use cases I am aware of are for client applications. They are not only for web JS though; Android and Swift SDKs have the same use cases. There might be other use cases for non-client applications that I am not aware of; perhaps I should move this discussion to the spec repo.

Which component is responsible for such global changes?

It would not be an instrumentation. I envision this to be similar to resource providers.

Is it allowed to have more parallel sessions running?

I don't think there would be multiple parallel sessions, at least not represented using the same attribute. But I think this can be a separate conversation independent of how global attributes are handled in general.

Is it allowed that spans on the same trace are on different sessions?

Good question, I would say no, but it needs to be defined.

Copy link

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days.

Copy link

github-actions bot commented Mar 4, 2024

This issue was closed because it has been stale for 14 days with no activity.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Mar 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Discussion Issue or PR that needs/is extended discussion. stale
Projects
None yet
Development

No branches or pull requests

3 participants