Skip to content

Commit

Permalink
pynipap: Merged to single file
Browse files Browse the repository at this point in the history
To avoid hogging the global name "tracing", merged tracing.py into
pynipap.py.
  • Loading branch information
garberg committed Aug 14, 2024
1 parent 703192b commit 719d78b
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 159 deletions.
152 changes: 150 additions & 2 deletions pynipap/pynipap.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@
import logging
import xmlrpc.client as xmlrpclib
import urllib.parse

from tracing import create_span
import inspect
from functools import wraps

__version__ = "0.32.5"
__author__ = "Kristian Larsson, Lukas Garberg"
Expand All @@ -229,6 +229,154 @@
# disable for long running applications.
CACHE = True


# Try to initiate tracing
try:
from opentelemetry import trace, context
from opentelemetry.trace import SpanKind, INVALID_SPAN
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.trace.sampling import DEFAULT_ON
import opentelemetry.exporter.otlp.proto.http.trace_exporter

tracer = trace.get_tracer("pynipap")


def init_tracing(service_name, endpoint, sampler, use_grpc=True):
resource = Resource(attributes={
SERVICE_NAME: service_name
})

if sampler is None:
sampler = DEFAULT_ON

provider = TracerProvider(sampler=sampler, resource=resource)
if use_grpc:
processor = BatchSpanProcessor(OTLPSpanExporter(endpoint=endpoint))
else:
processor = BatchSpanProcessor(
opentelemetry.exporter.otlp.proto.http.trace_exporter.OTLPSpanExporter(endpoint=endpoint))
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)


def create_span(f):
""" Class decorator creating a opentelemetry span
"""

@wraps(f)
def decorated(*args, **kwargs):
"""
"""

signature = inspect.signature(f)

if args[0].__class__ == type:
span_name = args[0].__name__ + " " + f.__name__
else:
span_name = str(args[0].__class__.__name__) + " " + f.__name__

with tracer.start_as_current_span(span_name,
context.get_current(),
SpanKind.CLIENT):
index = 0
span = trace.get_current_span()
for parameter in signature.parameters:
if index > 0:
try:
span.set_attribute("argument." + parameter, str(args[index]))
except IndexError:
break
index += 1
try:
span.set_attribute("username", AuthOptions().options['username'])
span.set_attribute("authoritative_source", AuthOptions().options['authoritative_source'])
except BaseException:
pass
return f(*args, **kwargs)

return decorated


class TracingXMLTransport(xmlrpclib.Transport):

def __init__(self, use_datetime=False, use_builtin_types=False,
*, headers=()):
super().__init__(use_datetime=use_datetime,
use_builtin_types=use_builtin_types,
headers=headers)

def request(self, host, handler, request_body, verbose=False):
with tracer.start_as_current_span("POST XML request", context.get_current(), SpanKind.CLIENT):
current_span = trace.get_current_span()
try:
result = super().request(host, handler, request_body, verbose)
current_span.set_attribute("http.status_code", 200)
except xmlrpclib.ProtocolError as protocolError:
current_span.set_attribute("http.status_code", protocolError.errcode)
current_span.record_exception(protocolError)
raise protocolError
return result

def send_content(self, connection, request_body):
current_span = trace.get_current_span()
if current_span != INVALID_SPAN:
current_span.set_attribute("net.peer.ip", connection.host)
current_span.set_attribute("net.peer.port", connection.port)
current_span.set_attribute("net.peer.transport", "ip_tcp")
connection.putheader("traceparent",
"00-" + hex(current_span.get_span_context().trace_id)[2:].zfill(32) + "-" + hex(
current_span.get_span_context().span_id)[2:].zfill(16) + "-0" + ("1" if current_span.is_recording() else "0"))

super().send_content(connection, request_body)


class TracingXMLSafeTransport(xmlrpclib.SafeTransport):

def __init__(self, use_datetime=False, use_builtin_types=False,
*, headers=(), context=None):
super().__init__(use_datetime=use_datetime,
use_builtin_types=use_builtin_types,
headers=headers, context=context)

def request(self, host, handler, request_body, verbose=False):
with tracer.start_as_current_span("POST XML request", context.get_current(), SpanKind.CLIENT):
current_span = trace.get_current_span()
try:
result = super().request(host, handler, request_body, verbose)
current_span.set_attribute("http.status_code", 200)
except xmlrpclib.ProtocolError as protocolError:
current_span.set_attribute("http.status_code", protocolError.errcode)
current_span.record_exception(protocolError)
raise protocolError
return result

def send_content(self, connection, request_body):
current_span = trace.get_current_span()
if current_span != INVALID_SPAN:
current_span.set_attribute("net.peer.ip", connection.host)
current_span.set_attribute("net.peer.port", connection.port)
current_span.set_attribute("net.peer.transport", "ip_tcp")
connection.putheader("traceparent",
"00-" + hex(current_span.get_span_context().trace_id)[2:].zfill(32) + "-" + hex(
current_span.get_span_context().span_id)[2:].zfill(16) + "-0" + ("1" if current_span.is_recording() else "0"))

super().send_content(connection, request_body)

except ImportError:
def create_span(f):
@wraps(f)
def decorated(*args, **kwargs):
return f(*args, **kwargs)

return decorated

def init_tracing(service_name, endpoint, sampler, use_grpc=True):
raise ImportError("Opentelemetry dependencies are missing")


class AuthOptions:
""" A global-ish authentication option container.
Expand Down
2 changes: 1 addition & 1 deletion pynipap/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
author_email = pynipap.__author_email__,
license = pynipap.__license__,
url = pynipap.__url__,
py_modules = ['pynipap','tracing'],
py_modules = ['pynipap'],
keywords = ['nipap'],
classifiers = [
'Development Status :: 4 - Beta',
Expand Down
156 changes: 0 additions & 156 deletions pynipap/tracing.py

This file was deleted.

0 comments on commit 719d78b

Please sign in to comment.