mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-29 13:12:39 +08:00
Logging instr hook (#1117)
This commit is contained in:
@ -15,11 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- cleanup type hints for textmap `Getter` and `Setter` classes
|
- cleanup type hints for textmap `Getter` and `Setter` classes
|
||||||
([1106](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1106))
|
([1106](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1106))
|
||||||
|
|
||||||
### Added
|
|
||||||
- `opentelemetry-instrumentation-remoulade` Initial release
|
|
||||||
([#1082](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1082))
|
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- `opentelemetry-instrumentation-logging` add log hook support
|
||||||
|
([#1117](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1117))
|
||||||
|
- `opentelemetry-instrumentation-remoulade` Initial release
|
||||||
|
([#1082](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1082))
|
||||||
- Added `opentelemetry-instrumention-confluent-kafka`
|
- Added `opentelemetry-instrumention-confluent-kafka`
|
||||||
([#1111](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1111))
|
([#1111](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1111))
|
||||||
|
|
||||||
|
@ -55,6 +55,10 @@ class LoggingInstrumentor(BaseInstrumentor): # pylint: disable=empty-docstring
|
|||||||
|
|
||||||
{DEFAULT_LOGGING_FORMAT}
|
{DEFAULT_LOGGING_FORMAT}
|
||||||
|
|
||||||
|
def log_hook(span: Span, record: LogRecord):
|
||||||
|
if span and span.is_recording():
|
||||||
|
record.custom_user_attribute_from_log_hook = "some-value"
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
tracer_provider: Tracer provider instance that can be used to fetch a tracer.
|
tracer_provider: Tracer provider instance that can be used to fetch a tracer.
|
||||||
set_logging_format: When set to True, it calls logging.basicConfig() and sets a logging format.
|
set_logging_format: When set to True, it calls logging.basicConfig() and sets a logging format.
|
||||||
@ -66,11 +70,13 @@ class LoggingInstrumentor(BaseInstrumentor): # pylint: disable=empty-docstring
|
|||||||
logging.WARN
|
logging.WARN
|
||||||
logging.ERROR
|
logging.ERROR
|
||||||
logging.FATAL
|
logging.FATAL
|
||||||
|
log_hook: execute custom logic when record is created
|
||||||
|
|
||||||
See `BaseInstrumentor`
|
See `BaseInstrumentor`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_old_factory = None
|
_old_factory = None
|
||||||
|
_log_hook = None
|
||||||
|
|
||||||
def instrumentation_dependencies(self) -> Collection[str]:
|
def instrumentation_dependencies(self) -> Collection[str]:
|
||||||
return _instruments
|
return _instruments
|
||||||
@ -80,6 +86,7 @@ class LoggingInstrumentor(BaseInstrumentor): # pylint: disable=empty-docstring
|
|||||||
provider = kwargs.get("tracer_provider", None) or get_tracer_provider()
|
provider = kwargs.get("tracer_provider", None) or get_tracer_provider()
|
||||||
old_factory = logging.getLogRecordFactory()
|
old_factory = logging.getLogRecordFactory()
|
||||||
LoggingInstrumentor._old_factory = old_factory
|
LoggingInstrumentor._old_factory = old_factory
|
||||||
|
LoggingInstrumentor._log_hook = kwargs.get("log_hook", None)
|
||||||
|
|
||||||
service_name = None
|
service_name = None
|
||||||
|
|
||||||
@ -107,6 +114,14 @@ class LoggingInstrumentor(BaseInstrumentor): # pylint: disable=empty-docstring
|
|||||||
if ctx != INVALID_SPAN_CONTEXT:
|
if ctx != INVALID_SPAN_CONTEXT:
|
||||||
record.otelSpanID = format(ctx.span_id, "016x")
|
record.otelSpanID = format(ctx.span_id, "016x")
|
||||||
record.otelTraceID = format(ctx.trace_id, "032x")
|
record.otelTraceID = format(ctx.trace_id, "032x")
|
||||||
|
if callable(LoggingInstrumentor._log_hook):
|
||||||
|
try:
|
||||||
|
LoggingInstrumentor._log_hook( # pylint: disable=E1102
|
||||||
|
span, record
|
||||||
|
)
|
||||||
|
except Exception: # pylint: disable=W0703
|
||||||
|
pass
|
||||||
|
|
||||||
return record
|
return record
|
||||||
|
|
||||||
logging.setLogRecordFactory(record_factory)
|
logging.setLogRecordFactory(record_factory)
|
||||||
|
@ -64,6 +64,10 @@ class TestLoggingInstrumentorProxyTracerProvider(TestBase):
|
|||||||
self.assertEqual(record.otelServiceName, "")
|
self.assertEqual(record.otelServiceName, "")
|
||||||
|
|
||||||
|
|
||||||
|
def log_hook(span, record):
|
||||||
|
record.custom_user_attribute_from_log_hook = "some-value"
|
||||||
|
|
||||||
|
|
||||||
class TestLoggingInstrumentor(TestBase):
|
class TestLoggingInstrumentor(TestBase):
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def inject_fixtures(self, caplog):
|
def inject_fixtures(self, caplog):
|
||||||
@ -150,6 +154,27 @@ class TestLoggingInstrumentor(TestBase):
|
|||||||
format="%(message)s span_id=%(otelSpanID)s", level=logging.WARNING
|
format="%(message)s span_id=%(otelSpanID)s", level=logging.WARNING
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_log_hook(self):
|
||||||
|
LoggingInstrumentor().uninstrument()
|
||||||
|
LoggingInstrumentor().instrument(
|
||||||
|
set_logging_format=True,
|
||||||
|
log_hook=log_hook,
|
||||||
|
)
|
||||||
|
with self.tracer.start_as_current_span("s1") as span:
|
||||||
|
span_id = format(span.get_span_context().span_id, "016x")
|
||||||
|
trace_id = format(span.get_span_context().trace_id, "032x")
|
||||||
|
with self.caplog.at_level(level=logging.INFO):
|
||||||
|
logger = logging.getLogger("test logger")
|
||||||
|
logger.info("hello")
|
||||||
|
self.assertEqual(len(self.caplog.records), 1)
|
||||||
|
record = self.caplog.records[0]
|
||||||
|
self.assertEqual(record.otelSpanID, span_id)
|
||||||
|
self.assertEqual(record.otelTraceID, trace_id)
|
||||||
|
self.assertEqual(record.otelServiceName, "unknown_service")
|
||||||
|
self.assertEqual(
|
||||||
|
record.custom_user_attribute_from_log_hook, "some-value"
|
||||||
|
)
|
||||||
|
|
||||||
def test_uninstrumented(self):
|
def test_uninstrumented(self):
|
||||||
with self.tracer.start_as_current_span("s1") as span:
|
with self.tracer.start_as_current_span("s1") as span:
|
||||||
span_id = format(span.get_span_context().span_id, "016x")
|
span_id = format(span.get_span_context().span_id, "016x")
|
||||||
|
Reference in New Issue
Block a user