open-telemetry/oteps

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:

image

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 of instrumentation 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 by name, where tracers and loggers can be wired to different exporters; where configuration itself may also supply additional details, such as Instrumentation Key or Authorization Key or Storage Destination for a given Named Tracer or Named 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.