mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
opentelemetry callback: context propagation and error exception (#3378)
* opentelemetry callback: context propagation and error exception * Apply suggestions from code review Co-authored-by: Felix Fontein <felix@fontein.de> Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
b20fc7a7c3
commit
06345839c6
1 changed files with 26 additions and 4 deletions
|
@ -30,6 +30,13 @@ DOCUMENTATION = '''
|
||||||
- The service name resource attribute.
|
- The service name resource attribute.
|
||||||
env:
|
env:
|
||||||
- name: OTEL_SERVICE_NAME
|
- name: OTEL_SERVICE_NAME
|
||||||
|
traceparent:
|
||||||
|
default: None
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
- The L(W3C Trace Context header traceparent,https://www.w3.org/TR/trace-context-1/#traceparent-header).
|
||||||
|
env:
|
||||||
|
- name: TRACEPARENT
|
||||||
requirements:
|
requirements:
|
||||||
- opentelemetry-api (python lib)
|
- opentelemetry-api (python lib)
|
||||||
- opentelemetry-exporter-otlp (python lib)
|
- opentelemetry-exporter-otlp (python lib)
|
||||||
|
@ -64,9 +71,11 @@ from ansible.plugins.callback import CallbackBase
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from opentelemetry import trace
|
from opentelemetry import trace
|
||||||
|
from opentelemetry.trace import SpanKind
|
||||||
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
||||||
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
||||||
from opentelemetry.trace.status import Status, StatusCode
|
from opentelemetry.trace.status import Status, StatusCode
|
||||||
|
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
||||||
from opentelemetry.sdk.trace import TracerProvider
|
from opentelemetry.sdk.trace import TracerProvider
|
||||||
from opentelemetry.sdk.trace.export import (
|
from opentelemetry.sdk.trace.export import (
|
||||||
ConsoleSpanExporter,
|
ConsoleSpanExporter,
|
||||||
|
@ -151,6 +160,11 @@ class OpenTelemetrySource(object):
|
||||||
|
|
||||||
self._display = display
|
self._display = display
|
||||||
|
|
||||||
|
def traceparent_context(self, traceparent):
|
||||||
|
carrier = dict()
|
||||||
|
carrier['traceparent'] = traceparent
|
||||||
|
return TraceContextTextMapPropagator().extract(carrier=carrier)
|
||||||
|
|
||||||
def start_task(self, tasks_data, hide_task_arguments, play_name, task):
|
def start_task(self, tasks_data, hide_task_arguments, play_name, task):
|
||||||
""" record the start of a task for one or more hosts """
|
""" record the start of a task for one or more hosts """
|
||||||
|
|
||||||
|
@ -188,7 +202,7 @@ class OpenTelemetrySource(object):
|
||||||
|
|
||||||
task.add_host(HostData(host_uuid, host_name, status, result))
|
task.add_host(HostData(host_uuid, host_name, status, result))
|
||||||
|
|
||||||
def generate_distributed_traces(self, otel_service_name, ansible_playbook, tasks_data, status):
|
def generate_distributed_traces(self, otel_service_name, ansible_playbook, tasks_data, status, traceparent):
|
||||||
""" generate distributed traces from the collected TaskData and HostData """
|
""" generate distributed traces from the collected TaskData and HostData """
|
||||||
|
|
||||||
tasks = []
|
tasks = []
|
||||||
|
@ -210,7 +224,8 @@ class OpenTelemetrySource(object):
|
||||||
|
|
||||||
tracer = trace.get_tracer(__name__)
|
tracer = trace.get_tracer(__name__)
|
||||||
|
|
||||||
with tracer.start_as_current_span(ansible_playbook, start_time=parent_start_time) as parent:
|
with tracer.start_as_current_span(ansible_playbook, context=self.traceparent_context(traceparent),
|
||||||
|
start_time=parent_start_time, kind=SpanKind.SERVER) as parent:
|
||||||
parent.set_status(status)
|
parent.set_status(status)
|
||||||
# Populate trace metadata attributes
|
# Populate trace metadata attributes
|
||||||
if self.ansible_version is not None:
|
if self.ansible_version is not None:
|
||||||
|
@ -244,7 +259,9 @@ class OpenTelemetrySource(object):
|
||||||
message = res['msg']
|
message = res['msg']
|
||||||
else:
|
else:
|
||||||
message = 'failed'
|
message = 'failed'
|
||||||
status = Status(status_code=StatusCode.ERROR)
|
status = Status(status_code=StatusCode.ERROR, description=message)
|
||||||
|
# Record an exception with the task message
|
||||||
|
span.record_exception(BaseException(message))
|
||||||
elif host_data.status == 'skipped':
|
elif host_data.status == 'skipped':
|
||||||
if 'skip_reason' in res:
|
if 'skip_reason' in res:
|
||||||
message = res['skip_reason']
|
message = res['skip_reason']
|
||||||
|
@ -291,6 +308,7 @@ class CallbackModule(CallbackBase):
|
||||||
self.tasks_data = None
|
self.tasks_data = None
|
||||||
self.errors = 0
|
self.errors = 0
|
||||||
self.disabled = False
|
self.disabled = False
|
||||||
|
self.traceparent = False
|
||||||
|
|
||||||
if OTEL_LIBRARY_IMPORT_ERROR:
|
if OTEL_LIBRARY_IMPORT_ERROR:
|
||||||
raise_from(
|
raise_from(
|
||||||
|
@ -318,6 +336,9 @@ class CallbackModule(CallbackBase):
|
||||||
if not self.otel_service_name:
|
if not self.otel_service_name:
|
||||||
self.otel_service_name = 'ansible'
|
self.otel_service_name = 'ansible'
|
||||||
|
|
||||||
|
# See https://github.com/open-telemetry/opentelemetry-specification/issues/740
|
||||||
|
self.traceparent = self.get_option('traceparent')
|
||||||
|
|
||||||
def v2_playbook_on_start(self, playbook):
|
def v2_playbook_on_start(self, playbook):
|
||||||
self.ansible_playbook = basename(playbook._file_name)
|
self.ansible_playbook = basename(playbook._file_name)
|
||||||
|
|
||||||
|
@ -394,7 +415,8 @@ class CallbackModule(CallbackBase):
|
||||||
self.otel_service_name,
|
self.otel_service_name,
|
||||||
self.ansible_playbook,
|
self.ansible_playbook,
|
||||||
self.tasks_data,
|
self.tasks_data,
|
||||||
status
|
status,
|
||||||
|
self.traceparent
|
||||||
)
|
)
|
||||||
|
|
||||||
def v2_runner_on_async_failed(self, result, **kwargs):
|
def v2_runner_on_async_failed(self, result, **kwargs):
|
||||||
|
|
Loading…
Reference in a new issue