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

NH-12018 oboe Reporter init moved to Configurator #17

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion opentelemetry_distro_solarwinds/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
EQUALS_W3C_SANITIZED = "####"
SW_TRACESTATE_KEY = "sw"
OTEL_CONTEXT_SW_OPTIONS_KEY = "sw_xtraceoptions"
OTEL_CONTEXT_SW_SIGNATURE_KEY = "sw_signature"
OTEL_CONTEXT_SW_SIGNATURE_KEY = "sw_signature"
DEFAULT_SW_TRACES_EXPORTER = "solarwinds_exporter"
151 changes: 116 additions & 35 deletions opentelemetry_distro_solarwinds/configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@
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 TracerProvider
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__)
Expand All @@ -32,55 +37,131 @@ class SolarWindsConfigurator(_OTelSDKConfigurator):
_DEFAULT_SW_TRACES_SAMPLER = "solarwinds_sampler"

def _configure(self, **kwargs):
environ_sampler = environ.get(
"""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):
"""Configure SolarWinds or env-specified OTel sampler"""
sampler = None
environ_sampler_name = environ.get(
OTEL_TRACES_SAMPLER,
self._DEFAULT_SW_TRACES_SAMPLER,
)
try:
sampler = load_entry_point(
"opentelemetry_distro_solarwinds",
"opentelemetry_traces_sampler",
environ_sampler
)()
except:
logger.exception(
"Failed to load configured sampler `%s`", environ_sampler
)
raise

if environ_sampler_name == self._DEFAULT_SW_TRACES_SAMPLER:
try:
sampler = load_entry_point(
"opentelemetry_distro_solarwinds",
"opentelemetry_traces_sampler",
environ_sampler_name
)()
except:
logger.exception(
"Failed to load configured sampler {}".format(
environ_sampler_name
)
)
raise
else:
# OTel SDK uses _get_from_env_or_default, not entrypoints
sampler = sampling._get_from_env_or_default()

trace.set_tracer_provider(
TracerProvider(sampler=sampler))
TracerProvider(sampler=sampler)
)

environ_exporter = environ.get(OTEL_TRACES_EXPORTER)
try:
exporter = load_entry_point(
"opentelemetry_distro_solarwinds",
"opentelemetry_traces_exporter",
environ_exporter
)()
except:
logger.exception(
"Failed to load configured exporter `%s`", environ_exporter
)
raise
span_exporter = BatchSpanProcessor(exporter)
trace.get_tracer_provider().add_span_processor(span_exporter)
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)

# Init and set CompositePropagator globally, like OTel API
environ_propagators = environ.get(OTEL_PROPAGATORS).split(",")
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 = []
for propagator in environ_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)
iter_entry_points("opentelemetry_propagator", propagator_name)
).load()()
)
except Exception:
logger.exception(
"Failed to load configured propagator `%s`", propagator
"Failed to load configured propagator {}".format(
propagator_name
)
)
raise
set_global_textmap(CompositePropagator(propagators))

# Set global HTTP response propagator
set_global_response_propagator(SolarWindsTraceResponsePropagator())
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,
)
10 changes: 5 additions & 5 deletions opentelemetry_distro_solarwinds/distro.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
OTEL_TRACES_EXPORTER
)
from opentelemetry.instrumentation.distro import BaseDistro
from opentelemetry.sdk.environment_variables import OTEL_TRACES_SAMPLER

from opentelemetry_distro_solarwinds import DEFAULT_SW_TRACES_EXPORTER

logger = logging.getLogger(__name__)

Expand All @@ -22,10 +23,10 @@ class SolarWindsDistro(BaseDistro):
"baggage",
_SW_PROPAGATOR,
]
_DEFAULT_SW_TRACES_EXPORTER = "solarwinds_exporter"

def _configure(self, **kwargs):
environ.setdefault(OTEL_TRACES_EXPORTER, self._DEFAULT_SW_TRACES_EXPORTER)
"""Configure OTel exporter and propagators"""
environ.setdefault(OTEL_TRACES_EXPORTER, DEFAULT_SW_TRACES_EXPORTER)

environ_propagators = environ.get(
OTEL_PROPAGATORS,
Expand All @@ -45,8 +46,7 @@ def _configure(self, **kwargs):
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_SAMPLER),
logger.debug("Configured SolarWindsDistro: {}, {}".format(
environ.get(OTEL_TRACES_EXPORTER),
environ.get(OTEL_PROPAGATORS)
))
49 changes: 8 additions & 41 deletions opentelemetry_distro_solarwinds/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,25 @@
"""

import logging
import os

from opentelemetry.sdk.trace.export import SpanExporter

from opentelemetry_distro_solarwinds.extension.oboe import (Context, Metadata,
Reporter)
from opentelemetry_distro_solarwinds.extension.oboe import (
Context,
Metadata
)
from opentelemetry_distro_solarwinds.w3c_transformer import W3CTransformer

logger = logging.getLogger(__file__)


class SolarWindsSpanExporter(SpanExporter):
"""SolarWinds span exporter.

Reports instrumentation data to the SolarWinds backend.
"""SolarWinds custom span exporter for the SolarWinds backend.
Initialization requires a liboboe reporter.
"""
def __init__(self, *args, **kw_args):
def __init__(self, reporter, *args, **kw_args):
super().__init__(*args, **kw_args)
self.reporter = None
self._initialize_solarwinds_reporter()
self.reporter = reporter

def export(self, spans):
"""Export to AO events and report via liboboe.
Expand Down Expand Up @@ -88,38 +87,6 @@ def _report_info_event(self, event):
evt.addInfo(k, v)
self.reporter.sendReport(evt, False)

def _initialize_solarwinds_reporter(self):
"""Initialize liboboe."""
log_level = os.environ.get('SOLARWINDS_DEBUG_LEVEL', 3)
try:
log_level = int(log_level)
except ValueError:
log_level = 3
self.reporter = 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=os.environ.get('SOLARWINDS_COLLECTOR', ''),
service_key=os.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,
)

@staticmethod
def _build_metadata(span_context):
return Metadata.fromString(
Expand Down