Proposal: Ability to associate tracer by alias with exporter/appender/destination
maxgolov opened this issue · 1 comments
Today's API
Currently TracerProvider.GetTracer(library_name, library_version)
. This API implies that one tracer provider is:
- single-tenant
- single-destination
- single-exporter
This is implied from statement that instrumentation library
must be supplied to Get Tracer, and that instrumentation library
is NOT the instrumented library
or module.
Quote:
library_name
and library_version
parameters and real-world multitenant applications
When a customer manually instruments with OpenTelemetry SDK, deploying their complex enterprise-grade application with no existing instrumentation library
, it would be of benefit to provide module name
rather than instrumentation library
as the first parameter to API. Different components of the app should be able to obtain each their own tracer, associated with their own instrumentationName
- as in their own component name, of the component being instrumented.
Proposal
It would be great to adjust the spec to allow for implementation dependent definition of instrumentationName
, i.e. first parameter passed to GetTracer
. Such as GetTracer(name)
, where name
- remains instrumentationName
, but its semantics could be either instrumentation library
name or instrumented module
name.
auto metaTracerProvider = GetConfigurableTracerProvider("configuration.file");
auto tracer1 = metaTracerProvider.GetTracer("com.acme.Module1");
auto tracer2 = metaTracerProvider.GetTracer("com.acme.Module2");
Further, having this implemented - we can provision a separate configuration piece, that allows to rewire the module by-name with given tracer, and/or instrumentation outside of code:
- named
tracer1
("com.acme.Module1") -> wired to Instrumentation A / Exporter A1 / Tenant1 - named
tracer2
("com.acme.Module2") -> wired to Instrumentation Library A / Exporter A2 / Tenant2
This approach would enable us:
-
to follow the best external config-provisioning practices established by Apache log4j and log4cxx
-
to allow for a single TracerProvider to enable configurable
different
destinations: same provider by-name could return different instrumentation libraries, and/or multiple exporters of the same library_name/version chained together. For example, provisioning an instance ofinstrumentation library
with different exporter arguments, to send data to different tenant in the cloud storage. -
provide ability to specify configurable destinations (outside of OTEL spec) - by
alias
or byname
, where tracers and loggers can be wired to different exporters; where configuration itself may also supply additional details, such asInstrumentation Key
orAuthorization Key
orStorage Destination
for a givenNamed Tracer
orNamed Logger
.
Conceptually the same should apply to Logger Provider too. In other words, TracerProvider.GetTracer(name)
or LoggerProvider.GetLogger(name)
- allows to rewire to same or different exporter dynamically at runtime, supplying additional configuration details (implementation dependent) outside of code. That way developer do not need to re-instrument (they can maintain the same module tracer/logger name), in case if ingestion/authorization key changes; OR if data ingestion destination URL changes; OR even if they decide to move to different exporter / cloud provider, they would only need to reprovision a different configuration for a given tracer or logger name.
One can define the config mapping like this, with exporter and options provisioned similar to how it's done in log4j :
Tracer (Logger) Name | Exporter | Exporter Options |
---|---|---|
console | Stream | |
Module1 | OTLP | host:port |
Module2 | AzMon | iKey=x,maxBatchSize=2MB,etc. |
That way it's easy to rewire the Module1
to whatever exporter, with whatever externally-provisioned options. Also one may either chain, or specify multiple exporters for the given tracer name. For example, allowing the same GetTracer("Module1")
to return an instance that would route incoming traces, events, logs, to more than one exporter.
For the Module2
example - if authorization key (iKey) used by Module2
changes, customers do not need to reinstrument their logic of acquiring the logger. They'll adjust the corresponding config. Or if the customer wants to migrate from one channel / provider, to another, i.e. if hosted on different clouds, they would not need to recompile their application. Name alias will bind their tracer to concrete library/version via config file rather than explicitly providing library name / version via API call.
Short Summary
In addition to GetTracer(library, version)
- introduce GetTracer(name)
, that allows for dynamic routing of named tracer or logger, i.e. allow the name
parameter to be anything. Could be library_name
. Could be something else, some other name, e.g. alias
or unique identifier
. That way a single TracerProvider (or meta provider) can be used to aggregate multiple exporters; can be used to dynamically route just single named tracer to /dev/null
, or provide additional attributes outside-of-code (in config file) that allow to route events emitted thru named
tracer to given destination.
What it gives - recap
Manageability. Once the logs or trace statements have been inserted into the code (for named loggers and tracers), they can be controlled with configuration files without code re-instrumentation. Loggers and Tracers can be selectively enabled or disabled, and sent / rewired to different and multiple output targets (different or multiple exporters) in user-chosen formats. Developers operate on named
tracers and loggers. Configuration covers the wiring aspects from instrumentationName
=> concrete tracer+exporter+configuration of a tracer in opaque manner. One can also develop a meta-TracerProvider that aggregates different kinds of underlying TracerProviders. That may subsequently retain the old semantics (library_name, library_version). In that flow, TenantModuleA
=> maps to library_X,version_Y,configOptions
.. Developer does GetTracer(TenantModuleA)
and a single TracerProvider
factory maps acquisition of a tracer to corresponding library, version, with given configuration / authentication settings.
I'm closing this since we resolved the inconsistency in spec. Once the other PR is merged (open-telemetry/opentelemetry-specification#1327) it becomes possible to implement what I described at individual SDK level.