-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from appoptics/add-custom-propagator
NH-2313 Add basic TraceState handling and W3C trace context propagation
- Loading branch information
Showing
12 changed files
with
1,016 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,10 @@ | ||
__version__ = "0.0.1" | ||
|
||
COMMA = "," | ||
COMMA_W3C_SANITIZED = "...." | ||
EQUALS = "=" | ||
EQUALS_W3C_SANITIZED = "####" | ||
SW_TRACESTATE_KEY = "sw" | ||
OTEL_CONTEXT_SW_OPTIONS_KEY = "sw_xtraceoptions" | ||
OTEL_CONTEXT_SW_SIGNATURE_KEY = "sw_signature" | ||
DEFAULT_SW_TRACES_EXPORTER = "solarwinds_exporter" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
"""Module to initialize OpenTelemetry SDK components to work with SolarWinds backend""" | ||
|
||
import logging | ||
from os import environ | ||
from pkg_resources import ( | ||
iter_entry_points, | ||
load_entry_point | ||
) | ||
|
||
from opentelemetry import trace | ||
from opentelemetry.environment_variables import ( | ||
OTEL_PROPAGATORS, | ||
OTEL_TRACES_EXPORTER | ||
) | ||
from opentelemetry.instrumentation.propagators import set_global_response_propagator | ||
from opentelemetry.propagate import set_global_textmap | ||
from opentelemetry.propagators.composite import CompositePropagator | ||
from opentelemetry.sdk._configuration import _OTelSDKConfigurator | ||
from opentelemetry.sdk.environment_variables import OTEL_TRACES_SAMPLER | ||
from opentelemetry.sdk.trace import ( | ||
sampling, | ||
TracerProvider | ||
) | ||
from opentelemetry.sdk.trace.export import BatchSpanProcessor | ||
|
||
from opentelemetry_distro_solarwinds import DEFAULT_SW_TRACES_EXPORTER | ||
from opentelemetry_distro_solarwinds.extension.oboe import Reporter | ||
from opentelemetry_distro_solarwinds.response_propagator import SolarWindsTraceResponsePropagator | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
class SolarWindsConfigurator(_OTelSDKConfigurator): | ||
"""OpenTelemetry Configurator for initializing SolarWinds-reporting SDK components""" | ||
|
||
# Cannot set as env default because not part of OTel Python _KNOWN_SAMPLERS | ||
# https://github.com/open-telemetry/opentelemetry-python/blob/main/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py#L364-L380 | ||
_DEFAULT_SW_TRACES_SAMPLER = "solarwinds_sampler" | ||
|
||
def _configure(self, **kwargs): | ||
"""Configure OTel sampler, exporter, propagator, response propagator""" | ||
reporter = self._initialize_solarwinds_reporter() | ||
self._configure_sampler() | ||
self._configure_exporter(reporter) | ||
self._configure_propagator() | ||
# Set global HTTP response propagator | ||
set_global_response_propagator(SolarWindsTraceResponsePropagator()) | ||
|
||
def _configure_sampler(self): | ||
"""Always configure SolarWinds OTel sampler""" | ||
try: | ||
sampler = load_entry_point( | ||
"opentelemetry_distro_solarwinds", | ||
"opentelemetry_traces_sampler", | ||
self._DEFAULT_SW_TRACES_SAMPLER | ||
)() | ||
except: | ||
logger.exception( | ||
"Failed to load configured sampler {}".format( | ||
self._DEFAULT_SW_TRACES_SAMPLER | ||
) | ||
) | ||
raise | ||
trace.set_tracer_provider( | ||
TracerProvider(sampler=sampler) | ||
) | ||
|
||
def _configure_exporter(self, reporter): | ||
"""Configure SolarWinds or env-specified OTel span exporter. | ||
Initialization of SolarWinds exporter requires a liboboe reporter.""" | ||
exporter = None | ||
environ_exporter_name = environ.get(OTEL_TRACES_EXPORTER) | ||
|
||
if environ_exporter_name == DEFAULT_SW_TRACES_EXPORTER: | ||
try: | ||
exporter = load_entry_point( | ||
"opentelemetry_distro_solarwinds", | ||
"opentelemetry_traces_exporter", | ||
environ_exporter_name | ||
)(reporter) | ||
except: | ||
logger.exception( | ||
"Failed to load configured exporter {} with reporter".format( | ||
environ_exporter_name | ||
) | ||
) | ||
raise | ||
else: | ||
try: | ||
exporter = next( | ||
iter_entry_points( | ||
"opentelemetry_traces_exporter", | ||
environ_exporter_name | ||
) | ||
).load()() | ||
except: | ||
logger.exception( | ||
"Failed to load configured exporter {}".format( | ||
environ_exporter_name | ||
) | ||
) | ||
raise | ||
span_processor = BatchSpanProcessor(exporter) | ||
trace.get_tracer_provider().add_span_processor(span_processor) | ||
|
||
def _configure_propagator(self): | ||
"""Configure CompositePropagator with SolarWinds and other propagators""" | ||
propagators = [] | ||
environ_propagators_names = environ.get(OTEL_PROPAGATORS).split(",") | ||
for propagator_name in environ_propagators_names: | ||
try: | ||
propagators.append( | ||
next( | ||
iter_entry_points("opentelemetry_propagator", propagator_name) | ||
).load()() | ||
) | ||
except Exception: | ||
logger.exception( | ||
"Failed to load configured propagator {}".format( | ||
propagator_name | ||
) | ||
) | ||
raise | ||
set_global_textmap(CompositePropagator(propagators)) | ||
|
||
def _initialize_solarwinds_reporter(self) -> Reporter: | ||
"""Initialize SolarWinds reporter used by sampler and exporter. This establishes collector and sampling settings in a background thread.""" | ||
log_level = environ.get('SOLARWINDS_DEBUG_LEVEL', 3) | ||
try: | ||
log_level = int(log_level) | ||
except ValueError: | ||
log_level = 3 | ||
# TODO make some of these customizable | ||
return Reporter( | ||
hostname_alias='', | ||
log_level=log_level, | ||
log_file_path='', | ||
max_transactions=-1, | ||
max_flush_wait_time=-1, | ||
events_flush_interval=-1, | ||
max_request_size_bytes=-1, | ||
reporter='ssl', | ||
host=environ.get('SOLARWINDS_COLLECTOR', ''), | ||
service_key=environ.get('SOLARWINDS_SERVICE_KEY', ''), | ||
trusted_path='', | ||
buffer_size=-1, | ||
trace_metrics=-1, | ||
histogram_precision=-1, | ||
token_bucket_capacity=-1, | ||
token_bucket_rate=-1, | ||
file_single=0, | ||
ec2_metadata_timeout=1000, | ||
grpc_proxy='', | ||
stdout_clear_nonblocking=0, | ||
is_grpc_clean_hack_enabled=False, | ||
w3c_trace_format=1, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,52 @@ | ||
"""Module to configure OpenTelemetry agent to work with SolarWinds backend""" | ||
"""Module to configure OpenTelemetry to work with SolarWinds backend""" | ||
|
||
from opentelemetry import trace | ||
import logging | ||
from os import environ | ||
|
||
from opentelemetry.environment_variables import ( | ||
OTEL_PROPAGATORS, | ||
OTEL_TRACES_EXPORTER | ||
) | ||
from opentelemetry.instrumentation.distro import BaseDistro | ||
from opentelemetry.sdk.trace import TracerProvider | ||
from opentelemetry.sdk.trace.export import BatchSpanProcessor | ||
|
||
from opentelemetry_distro_solarwinds.exporter import SolarWindsSpanExporter | ||
from opentelemetry_distro_solarwinds.sampler import ParentBasedAoSampler | ||
from opentelemetry_distro_solarwinds import DEFAULT_SW_TRACES_EXPORTER | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
class SolarWindsDistro(BaseDistro): | ||
"""SolarWinds custom distro for OpenTelemetry agents. | ||
"""OpenTelemetry Distro for SolarWinds reporting environment""" | ||
|
||
_TRACECONTEXT_PROPAGATOR = "tracecontext" | ||
_SW_PROPAGATOR = "solarwinds_propagator" | ||
_DEFAULT_SW_PROPAGATORS = [ | ||
_TRACECONTEXT_PROPAGATOR, | ||
"baggage", | ||
_SW_PROPAGATOR, | ||
] | ||
|
||
With this custom distro, the following functionality is introduced: | ||
- no functionality added at this time | ||
""" | ||
def _configure(self, **kwargs): | ||
# automatically make use of custom SolarWinds sampler | ||
trace.set_tracer_provider( | ||
TracerProvider(sampler=ParentBasedAoSampler())) | ||
# Automatically configure the SolarWinds Span exporter | ||
span_exporter = BatchSpanProcessor(SolarWindsSpanExporter()) | ||
trace.get_tracer_provider().add_span_processor(span_exporter) | ||
"""Configure OTel exporter and propagators""" | ||
environ.setdefault(OTEL_TRACES_EXPORTER, DEFAULT_SW_TRACES_EXPORTER) | ||
|
||
environ_propagators = environ.get( | ||
OTEL_PROPAGATORS, | ||
",".join(self._DEFAULT_SW_PROPAGATORS) | ||
).split(",") | ||
# If not using the default propagators, | ||
# can any arbitrary list BUT | ||
# (1) must include tracecontext and solarwinds_propagator | ||
# (2) tracecontext must be before solarwinds_propagator | ||
if environ_propagators != self._DEFAULT_SW_PROPAGATORS: | ||
if not self._TRACECONTEXT_PROPAGATOR in environ_propagators or \ | ||
not self._SW_PROPAGATOR in environ_propagators: | ||
raise ValueError("Must include tracecontext and solarwinds_propagator in OTEL_PROPAGATORS to use SolarWinds Observability.") | ||
|
||
if environ_propagators.index(self._SW_PROPAGATOR) \ | ||
< environ_propagators.index(self._TRACECONTEXT_PROPAGATOR): | ||
raise ValueError("tracecontext must be before solarwinds_propagator in OTEL_PROPAGATORS to use SolarWinds Observability.") | ||
environ[OTEL_PROPAGATORS] = ",".join(environ_propagators) | ||
|
||
logger.debug("Configured SolarWindsDistro: {}, {}".format( | ||
environ.get(OTEL_TRACES_EXPORTER), | ||
environ.get(OTEL_PROPAGATORS) | ||
)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.