diff --git a/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/_log_encoder/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/_log_encoder/__init__.py index 7213f89d4a0..02efbfe4cf0 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/_log_encoder/__init__.py +++ b/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/_log_encoder/__init__.py @@ -30,44 +30,44 @@ ResourceLogs, ScopeLogs, ) -from opentelemetry.sdk._logs import LogData +from opentelemetry.sdk._logs import LogRecord as SDKLogRecord -def encode_logs(batch: Sequence[LogData]) -> ExportLogsServiceRequest: +def encode_logs(batch: Sequence[SDKLogRecord]) -> ExportLogsServiceRequest: return ExportLogsServiceRequest(resource_logs=_encode_resource_logs(batch)) -def _encode_log(log_data: LogData) -> PB2LogRecord: +def _encode_log(log_record: SDKLogRecord) -> PB2LogRecord: span_id = ( None - if log_data.log_record.span_id == 0 - else _encode_span_id(log_data.log_record.span_id) + if log_record.span_id == 0 + else _encode_span_id(log_record.span_id) ) trace_id = ( None - if log_data.log_record.trace_id == 0 - else _encode_trace_id(log_data.log_record.trace_id) + if log_record.trace_id == 0 + else _encode_trace_id(log_record.trace_id) ) - body = log_data.log_record.body + body = log_record.body return PB2LogRecord( - time_unix_nano=log_data.log_record.timestamp, - observed_time_unix_nano=log_data.log_record.observed_timestamp, + time_unix_nano=log_record.timestamp, + observed_time_unix_nano=log_record.observed_timestamp, span_id=span_id, trace_id=trace_id, - flags=int(log_data.log_record.trace_flags), + flags=int(log_record.trace_flags), body=_encode_value(body) if body is not None else None, - severity_text=log_data.log_record.severity_text, - attributes=_encode_attributes(log_data.log_record.attributes), - dropped_attributes_count=log_data.log_record.dropped_attributes, - severity_number=log_data.log_record.severity_number.value, + severity_text=log_record.severity_text, + attributes=_encode_attributes(log_record.attributes), + dropped_attributes_count=log_record.dropped_attributes, + severity_number=log_record.severity_number.value, ) -def _encode_resource_logs(batch: Sequence[LogData]) -> List[ResourceLogs]: +def _encode_resource_logs(batch: Sequence[SDKLogRecord]) -> List[ResourceLogs]: sdk_resource_logs = defaultdict(lambda: defaultdict(list)) for sdk_log in batch: - sdk_resource = sdk_log.log_record.resource + sdk_resource = sdk_log.resource sdk_instrumentation = sdk_log.instrumentation_scope or None pb2_log = _encode_log(sdk_log) diff --git a/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_log_encoder.py b/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_log_encoder.py index 70f4c821c9e..433f748e8c5 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_log_encoder.py +++ b/exporter/opentelemetry-exporter-otlp-proto-common/tests/test_log_encoder.py @@ -39,7 +39,7 @@ from opentelemetry.proto.resource.v1.resource_pb2 import ( Resource as PB2Resource, ) -from opentelemetry.sdk._logs import LogData, LogLimits +from opentelemetry.sdk._logs import LogLimits from opentelemetry.sdk._logs import LogRecord as SDKLogRecord from opentelemetry.sdk.resources import Resource as SDKResource from opentelemetry.sdk.util.instrumentation import InstrumentationScope @@ -54,7 +54,7 @@ def test_encode(self): def test_encode_no_body(self): sdk_logs, expected_encoding = self.get_test_logs() for log in sdk_logs: - log.log_record.body = None + log.body = None for resource_log in expected_encoding.resource_logs: for scope_log in resource_log.scope_logs: @@ -66,7 +66,7 @@ def test_encode_no_body(self): def test_dropped_attributes_count(self): sdk_logs = self._get_test_logs_dropped_attributes() encoded_logs = encode_logs(sdk_logs) - self.assertTrue(hasattr(sdk_logs[0].log_record, "dropped_attributes")) + self.assertTrue(hasattr(sdk_logs[0], "dropped_attributes")) self.assertEqual( # pylint:disable=no-member encoded_logs.resource_logs[0] @@ -77,78 +77,70 @@ def test_dropped_attributes_count(self): ) @staticmethod - def _get_sdk_log_data() -> List[LogData]: - log1 = LogData( - log_record=SDKLogRecord( - timestamp=1644650195189786880, - observed_timestamp=1644650195189786881, - trace_id=89564621134313219400156819398935297684, - span_id=1312458408527513268, - trace_flags=TraceFlags(0x01), - severity_text="WARN", - severity_number=SeverityNumber.WARN, - body="Do not go gentle into that good night. Rage, rage against the dying of the light", - resource=SDKResource( - {"first_resource": "value"}, - "resource_schema_url", - ), - attributes={"a": 1, "b": "c"}, + def _get_sdk_log_data() -> List[SDKLogRecord]: + log1 = SDKLogRecord( + timestamp=1644650195189786880, + observed_timestamp=1644650195189786881, + trace_id=89564621134313219400156819398935297684, + span_id=1312458408527513268, + trace_flags=TraceFlags(0x01), + severity_text="WARN", + severity_number=SeverityNumber.WARN, + body="Do not go gentle into that good night. Rage, rage against the dying of the light", + resource=SDKResource( + {"first_resource": "value"}, + "resource_schema_url", ), + attributes={"a": 1, "b": "c"}, instrumentation_scope=InstrumentationScope( "first_name", "first_version" ), ) - log2 = LogData( - log_record=SDKLogRecord( - timestamp=1644650249738562048, - observed_timestamp=1644650249738562049, - trace_id=0, - span_id=0, - trace_flags=TraceFlags.DEFAULT, - severity_text="WARN", - severity_number=SeverityNumber.WARN, - body="Cooper, this is no time for caution!", - resource=SDKResource({"second_resource": "CASE"}), - attributes={}, - ), + log2 = SDKLogRecord( + timestamp=1644650249738562048, + observed_timestamp=1644650249738562049, + trace_id=0, + span_id=0, + trace_flags=TraceFlags.DEFAULT, + severity_text="WARN", + severity_number=SeverityNumber.WARN, + body="Cooper, this is no time for caution!", + resource=SDKResource({"second_resource": "CASE"}), + attributes={}, instrumentation_scope=InstrumentationScope( "second_name", "second_version" ), ) - log3 = LogData( - log_record=SDKLogRecord( - timestamp=1644650427658989056, - observed_timestamp=1644650427658989057, - trace_id=271615924622795969659406376515024083555, - span_id=4242561578944770265, - trace_flags=TraceFlags(0x01), - severity_text="DEBUG", - severity_number=SeverityNumber.DEBUG, - body="To our galaxy", - resource=SDKResource({"second_resource": "CASE"}), - attributes={"a": 1, "b": "c"}, - ), + log3 = SDKLogRecord( + timestamp=1644650427658989056, + observed_timestamp=1644650427658989057, + trace_id=271615924622795969659406376515024083555, + span_id=4242561578944770265, + trace_flags=TraceFlags(0x01), + severity_text="DEBUG", + severity_number=SeverityNumber.DEBUG, + body="To our galaxy", + resource=SDKResource({"second_resource": "CASE"}), + attributes={"a": 1, "b": "c"}, instrumentation_scope=None, ) - log4 = LogData( - log_record=SDKLogRecord( - timestamp=1644650584292683008, - observed_timestamp=1644650584292683009, - trace_id=212592107417388365804938480559624925555, - span_id=6077757853989569223, - trace_flags=TraceFlags(0x01), - severity_text="INFO", - severity_number=SeverityNumber.INFO, - body="Love is the one thing that transcends time and space", - resource=SDKResource( - {"first_resource": "value"}, - "resource_schema_url", - ), - attributes={"filename": "model.py", "func_name": "run_method"}, + log4 = SDKLogRecord( + timestamp=1644650584292683008, + observed_timestamp=1644650584292683009, + trace_id=212592107417388365804938480559624925555, + span_id=6077757853989569223, + trace_flags=TraceFlags(0x01), + severity_text="INFO", + severity_number=SeverityNumber.INFO, + body="Love is the one thing that transcends time and space", + resource=SDKResource( + {"first_resource": "value"}, + "resource_schema_url", ), + attributes={"filename": "model.py", "func_name": "run_method"}, instrumentation_scope=InstrumentationScope( "another_name", "another_version" ), @@ -293,37 +285,33 @@ def get_test_logs( return sdk_logs, pb2_service_request @staticmethod - def _get_test_logs_dropped_attributes() -> List[LogData]: - log1 = LogData( - log_record=SDKLogRecord( - timestamp=1644650195189786880, - trace_id=89564621134313219400156819398935297684, - span_id=1312458408527513268, - trace_flags=TraceFlags(0x01), - severity_text="WARN", - severity_number=SeverityNumber.WARN, - body="Do not go gentle into that good night. Rage, rage against the dying of the light", - resource=SDKResource({"first_resource": "value"}), - attributes={"a": 1, "b": "c", "user_id": "B121092"}, - limits=LogLimits(max_attributes=1), - ), + def _get_test_logs_dropped_attributes() -> List[SDKLogRecord]: + log1 = SDKLogRecord( + timestamp=1644650195189786880, + trace_id=89564621134313219400156819398935297684, + span_id=1312458408527513268, + trace_flags=TraceFlags(0x01), + severity_text="WARN", + severity_number=SeverityNumber.WARN, + body="Do not go gentle into that good night. Rage, rage against the dying of the light", + resource=SDKResource({"first_resource": "value"}), + attributes={"a": 1, "b": "c", "user_id": "B121092"}, + limits=LogLimits(max_attributes=1), instrumentation_scope=InstrumentationScope( "first_name", "first_version" ), ) - log2 = LogData( - log_record=SDKLogRecord( - timestamp=1644650249738562048, - trace_id=0, - span_id=0, - trace_flags=TraceFlags.DEFAULT, - severity_text="WARN", - severity_number=SeverityNumber.WARN, - body="Cooper, this is no time for caution!", - resource=SDKResource({"second_resource": "CASE"}), - attributes={}, - ), + log2 = SDKLogRecord( + timestamp=1644650249738562048, + trace_id=0, + span_id=0, + trace_flags=TraceFlags.DEFAULT, + severity_text="WARN", + severity_number=SeverityNumber.WARN, + body="Cooper, this is no time for caution!", + resource=SDKResource({"second_resource": "CASE"}), + attributes={}, instrumentation_scope=InstrumentationScope( "second_name", "second_version" ), diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py index 8f629899d77..309ba068315 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py @@ -28,7 +28,6 @@ from opentelemetry.proto.collector.logs.v1.logs_service_pb2_grpc import ( LogsServiceStub, ) -from opentelemetry.sdk._logs import LogData from opentelemetry.sdk._logs import LogRecord as SDKLogRecord from opentelemetry.sdk._logs.export import LogExporter, LogExportResult from opentelemetry.sdk.environment_variables import ( @@ -103,11 +102,11 @@ def __init__( ) def _translate_data( - self, data: Sequence[LogData] + self, data: Sequence[SDKLogRecord] ) -> ExportLogsServiceRequest: return encode_logs(data) - def export(self, batch: Sequence[LogData]) -> LogExportResult: + def export(self, batch: Sequence[SDKLogRecord]) -> LogExportResult: return self._export(batch) def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None: diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py index a31679fb0d5..24a510f2b52 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py @@ -52,7 +52,7 @@ from opentelemetry.proto.resource.v1.resource_pb2 import ( Resource as OTLPResource, ) -from opentelemetry.sdk._logs import LogData, LogRecord +from opentelemetry.sdk._logs import LogRecord from opentelemetry.sdk._logs.export import LogExportResult from opentelemetry.sdk.environment_variables import ( OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE, @@ -126,79 +126,70 @@ def setUp(self): self.server.start() - self.log_data_1 = LogData( - log_record=LogRecord( - timestamp=int(time.time() * 1e9), - trace_id=2604504634922341076776623263868986797, - span_id=5213367945872657620, - trace_flags=TraceFlags(0x01), - severity_text="WARNING", - severity_number=SeverityNumber.WARN, - body="Zhengzhou, We have a heaviest rains in 1000 years", - resource=SDKResource({"key": "value"}), - attributes={"a": 1, "b": "c"}, - ), + self.log_data_1 = LogRecord( + timestamp=int(time.time() * 1e9), + trace_id=2604504634922341076776623263868986797, + span_id=5213367945872657620, + trace_flags=TraceFlags(0x01), + severity_text="WARNING", + severity_number=SeverityNumber.WARN, + body="Zhengzhou, We have a heaviest rains in 1000 years", + resource=SDKResource({"key": "value"}), + attributes={"a": 1, "b": "c"}, instrumentation_scope=InstrumentationScope( "first_name", "first_version" ), ) - self.log_data_2 = LogData( - log_record=LogRecord( - timestamp=int(time.time() * 1e9), - trace_id=2604504634922341076776623263868986799, - span_id=5213367945872657623, - trace_flags=TraceFlags(0x01), - severity_text="INFO", - severity_number=SeverityNumber.INFO2, - body="Sydney, Opera House is closed", - resource=SDKResource({"key": "value"}), - attributes={"custom_attr": [1, 2, 3]}, - ), + self.log_data_2 = LogRecord( + timestamp=int(time.time() * 1e9), + trace_id=2604504634922341076776623263868986799, + span_id=5213367945872657623, + trace_flags=TraceFlags(0x01), + severity_text="INFO", + severity_number=SeverityNumber.INFO2, + body="Sydney, Opera House is closed", + resource=SDKResource({"key": "value"}), + attributes={"custom_attr": [1, 2, 3]}, instrumentation_scope=InstrumentationScope( "second_name", "second_version" ), ) - self.log_data_3 = LogData( - log_record=LogRecord( - timestamp=int(time.time() * 1e9), - trace_id=2604504634922341076776623263868986800, - span_id=5213367945872657628, - trace_flags=TraceFlags(0x01), - severity_text="ERROR", - severity_number=SeverityNumber.WARN, - body="Mumbai, Boil water before drinking", - resource=SDKResource({"service": "myapp"}), - ), + self.log_data_3 = LogRecord( + timestamp=int(time.time() * 1e9), + trace_id=2604504634922341076776623263868986800, + span_id=5213367945872657628, + trace_flags=TraceFlags(0x01), + severity_text="ERROR", + severity_number=SeverityNumber.WARN, + body="Mumbai, Boil water before drinking", + resource=SDKResource({"service": "myapp"}), instrumentation_scope=InstrumentationScope( "third_name", "third_version" ), ) - self.log_data_4 = LogData( - log_record=LogRecord( - timestamp=int(time.time() * 1e9), - trace_id=0, - span_id=5213367945872657629, - trace_flags=TraceFlags(0x01), - severity_text="ERROR", - severity_number=SeverityNumber.WARN, - body="Invalid trace id check", - resource=SDKResource({"service": "myapp"}), - ), + self.log_data_4 = LogRecord( + timestamp=int(time.time() * 1e9), + trace_id=0, + span_id=5213367945872657629, + trace_flags=TraceFlags(0x01), + severity_text="ERROR", + severity_number=SeverityNumber.WARN, + body="Invalid trace id check", + resource=SDKResource({"service": "myapp"}), instrumentation_scope=InstrumentationScope( "fourth_name", "fourth_version" ), ) - self.log_data_5 = LogData( - log_record=LogRecord( - timestamp=int(time.time() * 1e9), - trace_id=2604504634922341076776623263868986801, - span_id=0, - trace_flags=TraceFlags(0x01), - severity_text="ERROR", - severity_number=SeverityNumber.WARN, - body="Invalid span id check", - resource=SDKResource({"service": "myapp"}), - ), + + self.log_data_5 = LogRecord( + timestamp=int(time.time() * 1e9), + trace_id=2604504634922341076776623263868986801, + span_id=0, + trace_flags=TraceFlags(0x01), + severity_text="ERROR", + severity_number=SeverityNumber.WARN, + body="Invalid span id check", + resource=SDKResource({"service": "myapp"}), instrumentation_scope=InstrumentationScope( "fifth_name", "fifth_version" ), @@ -491,9 +482,9 @@ def test_translate_log_data(self): log_records=[ PB2LogRecord( # pylint: disable=no-member - time_unix_nano=self.log_data_1.log_record.timestamp, - observed_time_unix_nano=self.log_data_1.log_record.observed_timestamp, - severity_number=self.log_data_1.log_record.severity_number.value, + time_unix_nano=self.log_data_1.timestamp, + observed_time_unix_nano=self.log_data_1.observed_timestamp, + severity_number=self.log_data_1.severity_number.value, severity_text="WARNING", span_id=int.to_bytes( 5213367945872657620, 8, "big" @@ -516,9 +507,7 @@ def test_translate_log_data(self): value=AnyValue(string_value="c"), ), ], - flags=int( - self.log_data_1.log_record.trace_flags - ), + flags=int(self.log_data_1.trace_flags), ) ], ) @@ -551,9 +540,9 @@ def test_translate_multiple_logs(self): log_records=[ PB2LogRecord( # pylint: disable=no-member - time_unix_nano=self.log_data_1.log_record.timestamp, - observed_time_unix_nano=self.log_data_1.log_record.observed_timestamp, - severity_number=self.log_data_1.log_record.severity_number.value, + time_unix_nano=self.log_data_1.timestamp, + observed_time_unix_nano=self.log_data_1.observed_timestamp, + severity_number=self.log_data_1.severity_number.value, severity_text="WARNING", span_id=int.to_bytes( 5213367945872657620, 8, "big" @@ -576,9 +565,7 @@ def test_translate_multiple_logs(self): value=AnyValue(string_value="c"), ), ], - flags=int( - self.log_data_1.log_record.trace_flags - ), + flags=int(self.log_data_1.trace_flags), ) ], ), @@ -589,9 +576,9 @@ def test_translate_multiple_logs(self): log_records=[ PB2LogRecord( # pylint: disable=no-member - time_unix_nano=self.log_data_2.log_record.timestamp, - observed_time_unix_nano=self.log_data_2.log_record.observed_timestamp, - severity_number=self.log_data_2.log_record.severity_number.value, + time_unix_nano=self.log_data_2.timestamp, + observed_time_unix_nano=self.log_data_2.observed_timestamp, + severity_number=self.log_data_2.severity_number.value, severity_text="INFO", span_id=int.to_bytes( 5213367945872657623, 8, "big" @@ -610,9 +597,7 @@ def test_translate_multiple_logs(self): value=_encode_value([1, 2, 3]), ), ], - flags=int( - self.log_data_2.log_record.trace_flags - ), + flags=int(self.log_data_2.trace_flags), ) ], ), @@ -635,9 +620,9 @@ def test_translate_multiple_logs(self): log_records=[ PB2LogRecord( # pylint: disable=no-member - time_unix_nano=self.log_data_3.log_record.timestamp, - observed_time_unix_nano=self.log_data_3.log_record.observed_timestamp, - severity_number=self.log_data_3.log_record.severity_number.value, + time_unix_nano=self.log_data_3.timestamp, + observed_time_unix_nano=self.log_data_3.observed_timestamp, + severity_number=self.log_data_3.severity_number.value, severity_text="ERROR", span_id=int.to_bytes( 5213367945872657628, 8, "big" @@ -651,9 +636,7 @@ def test_translate_multiple_logs(self): "Mumbai, Boil water before drinking" ), attributes=[], - flags=int( - self.log_data_3.log_record.trace_flags - ), + flags=int(self.log_data_3.trace_flags), ) ], ) diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py index 21b877380c8..96f30df0d3f 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py @@ -30,7 +30,7 @@ _OTLP_HTTP_HEADERS, Compression, ) -from opentelemetry.sdk._logs import LogData +from opentelemetry.sdk._logs import LogRecord from opentelemetry.sdk._logs.export import ( LogExporter, LogExportResult, @@ -149,7 +149,7 @@ def _retryable(resp: requests.Response) -> bool: return True return False - def export(self, batch: Sequence[LogData]) -> LogExportResult: + def export(self, batch: Sequence[LogRecord]) -> LogExportResult: # After the call to Shutdown subsequent calls to Export are # not allowed and should return a Failure result. if self._shutdown: diff --git a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py index 66b0f890d76..c09718708af 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py @@ -35,7 +35,6 @@ from opentelemetry.proto.collector.logs.v1.logs_service_pb2 import ( ExportLogsServiceRequest, ) -from opentelemetry.sdk._logs import LogData from opentelemetry.sdk._logs import LogRecord as SDKLogRecord from opentelemetry.sdk._logs.export import LogExportResult from opentelemetry.sdk.environment_variables import ( @@ -214,18 +213,16 @@ def export_log_and_deserialize(log): return log_records def test_exported_log_without_trace_id(self): - log = LogData( - log_record=SDKLogRecord( - timestamp=1644650195189786182, - trace_id=0, - span_id=1312458408527513292, - trace_flags=TraceFlags(0x01), - severity_text="WARN", - severity_number=SeverityNumber.WARN, - body="Invalid trace id check", - resource=SDKResource({"first_resource": "value"}), - attributes={"a": 1, "b": "c"}, - ), + log = SDKLogRecord( + timestamp=1644650195189786182, + trace_id=0, + span_id=1312458408527513292, + trace_flags=TraceFlags(0x01), + severity_text="WARN", + severity_number=SeverityNumber.WARN, + body="Invalid trace id check", + resource=SDKResource({"first_resource": "value"}), + attributes={"a": 1, "b": "c"}, instrumentation_scope=InstrumentationScope("name", "version"), ) log_records = TestOTLPHTTPLogExporter.export_log_and_deserialize(log) @@ -241,18 +238,16 @@ def test_exported_log_without_trace_id(self): self.fail("No log records found") def test_exported_log_without_span_id(self): - log = LogData( - log_record=SDKLogRecord( - timestamp=1644650195189786360, - trace_id=89564621134313219400156819398935297696, - span_id=0, - trace_flags=TraceFlags(0x01), - severity_text="WARN", - severity_number=SeverityNumber.WARN, - body="Invalid span id check", - resource=SDKResource({"first_resource": "value"}), - attributes={"a": 1, "b": "c"}, - ), + log = SDKLogRecord( + timestamp=1644650195189786360, + trace_id=89564621134313219400156819398935297696, + span_id=0, + trace_flags=TraceFlags(0x01), + severity_text="WARN", + severity_number=SeverityNumber.WARN, + body="Invalid span id check", + resource=SDKResource({"first_resource": "value"}), + attributes={"a": 1, "b": "c"}, instrumentation_scope=InstrumentationScope("name", "version"), ) log_records = TestOTLPHTTPLogExporter.export_log_and_deserialize(log) @@ -287,68 +282,60 @@ def test_exponential_backoff(self, mock_sleep): ) @staticmethod - def _get_sdk_log_data() -> List[LogData]: - log1 = LogData( - log_record=SDKLogRecord( - timestamp=1644650195189786880, - trace_id=89564621134313219400156819398935297684, - span_id=1312458408527513268, - trace_flags=TraceFlags(0x01), - severity_text="WARN", - severity_number=SeverityNumber.WARN, - body="Do not go gentle into that good night. Rage, rage against the dying of the light", - resource=SDKResource({"first_resource": "value"}), - attributes={"a": 1, "b": "c"}, - ), + def _get_sdk_log_data() -> List[SDKLogRecord]: + log1 = SDKLogRecord( + timestamp=1644650195189786880, + trace_id=89564621134313219400156819398935297684, + span_id=1312458408527513268, + trace_flags=TraceFlags(0x01), + severity_text="WARN", + severity_number=SeverityNumber.WARN, + body="Do not go gentle into that good night. Rage, rage against the dying of the light", + resource=SDKResource({"first_resource": "value"}), + attributes={"a": 1, "b": "c"}, instrumentation_scope=InstrumentationScope( "first_name", "first_version" ), ) - log2 = LogData( - log_record=SDKLogRecord( - timestamp=1644650249738562048, - trace_id=0, - span_id=0, - trace_flags=TraceFlags.DEFAULT, - severity_text="WARN", - severity_number=SeverityNumber.WARN, - body="Cooper, this is no time for caution!", - resource=SDKResource({"second_resource": "CASE"}), - attributes={}, - ), + log2 = SDKLogRecord( + timestamp=1644650249738562048, + trace_id=0, + span_id=0, + trace_flags=TraceFlags.DEFAULT, + severity_text="WARN", + severity_number=SeverityNumber.WARN, + body="Cooper, this is no time for caution!", + resource=SDKResource({"second_resource": "CASE"}), + attributes={}, instrumentation_scope=InstrumentationScope( "second_name", "second_version" ), ) - log3 = LogData( - log_record=SDKLogRecord( - timestamp=1644650427658989056, - trace_id=271615924622795969659406376515024083555, - span_id=4242561578944770265, - trace_flags=TraceFlags(0x01), - severity_text="DEBUG", - severity_number=SeverityNumber.DEBUG, - body="To our galaxy", - resource=SDKResource({"second_resource": "CASE"}), - attributes={"a": 1, "b": "c"}, - ), + log3 = SDKLogRecord( + timestamp=1644650427658989056, + trace_id=271615924622795969659406376515024083555, + span_id=4242561578944770265, + trace_flags=TraceFlags(0x01), + severity_text="DEBUG", + severity_number=SeverityNumber.DEBUG, + body="To our galaxy", + resource=SDKResource({"second_resource": "CASE"}), + attributes={"a": 1, "b": "c"}, instrumentation_scope=None, ) - log4 = LogData( - log_record=SDKLogRecord( - timestamp=1644650584292683008, - trace_id=212592107417388365804938480559624925555, - span_id=6077757853989569223, - trace_flags=TraceFlags(0x01), - severity_text="INFO", - severity_number=SeverityNumber.INFO, - body="Love is the one thing that transcends time and space", - resource=SDKResource({"first_resource": "value"}), - attributes={"filename": "model.py", "func_name": "run_method"}, - ), + log4 = SDKLogRecord( + timestamp=1644650584292683008, + trace_id=212592107417388365804938480559624925555, + span_id=6077757853989569223, + trace_flags=TraceFlags(0x01), + severity_text="INFO", + severity_number=SeverityNumber.INFO, + body="Love is the one thing that transcends time and space", + resource=SDKResource({"first_resource": "value"}), + attributes={"filename": "model.py", "func_name": "run_method"}, instrumentation_scope=InstrumentationScope( "another_name", "another_version" ), diff --git a/opentelemetry-api/src/opentelemetry/_events/__init__.py b/opentelemetry-api/src/opentelemetry/_events/__init__.py deleted file mode 100644 index e1e6a675a52..00000000000 --- a/opentelemetry-api/src/opentelemetry/_events/__init__.py +++ /dev/null @@ -1,221 +0,0 @@ -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from abc import ABC, abstractmethod -from logging import getLogger -from os import environ -from typing import Any, Optional, cast - -from opentelemetry._logs import LogRecord -from opentelemetry._logs.severity import SeverityNumber -from opentelemetry.environment_variables import ( - _OTEL_PYTHON_EVENT_LOGGER_PROVIDER, -) -from opentelemetry.trace.span import TraceFlags -from opentelemetry.util._once import Once -from opentelemetry.util._providers import _load_provider -from opentelemetry.util.types import Attributes - -_logger = getLogger(__name__) - - -class Event(LogRecord): - def __init__( - self, - name: str, - timestamp: Optional[int] = None, - trace_id: Optional[int] = None, - span_id: Optional[int] = None, - trace_flags: Optional["TraceFlags"] = None, - body: Optional[Any] = None, - severity_number: Optional[SeverityNumber] = None, - attributes: Optional[Attributes] = None, - ): - attributes = attributes or {} - event_attributes = {**attributes, "event.name": name} - super().__init__( - timestamp=timestamp, - trace_id=trace_id, - span_id=span_id, - trace_flags=trace_flags, - body=body, # type: ignore - severity_number=severity_number, - attributes=event_attributes, - ) - self.name = name - - -class EventLogger(ABC): - def __init__( - self, - name: str, - version: Optional[str] = None, - schema_url: Optional[str] = None, - attributes: Optional[Attributes] = None, - ): - self._name = name - self._version = version - self._schema_url = schema_url - self._attributes = attributes - - @abstractmethod - def emit(self, event: "Event") -> None: - """Emits a :class:`Event` representing an event.""" - - -class NoOpEventLogger(EventLogger): - def emit(self, event: Event) -> None: - pass - - -class ProxyEventLogger(EventLogger): - def __init__( - self, - name: str, - version: Optional[str] = None, - schema_url: Optional[str] = None, - attributes: Optional[Attributes] = None, - ): - super().__init__( - name=name, - version=version, - schema_url=schema_url, - attributes=attributes, - ) - self._real_event_logger: Optional[EventLogger] = None - self._noop_event_logger = NoOpEventLogger(name) - - @property - def _event_logger(self) -> EventLogger: - if self._real_event_logger: - return self._real_event_logger - - if _EVENT_LOGGER_PROVIDER: - self._real_event_logger = _EVENT_LOGGER_PROVIDER.get_event_logger( - self._name, - self._version, - self._schema_url, - self._attributes, - ) - return self._real_event_logger - return self._noop_event_logger - - def emit(self, event: Event) -> None: - self._event_logger.emit(event) - - -class EventLoggerProvider(ABC): - @abstractmethod - def get_event_logger( - self, - name: str, - version: Optional[str] = None, - schema_url: Optional[str] = None, - attributes: Optional[Attributes] = None, - ) -> EventLogger: - """Returns an EventLoggerProvider for use.""" - - -class NoOpEventLoggerProvider(EventLoggerProvider): - def get_event_logger( - self, - name: str, - version: Optional[str] = None, - schema_url: Optional[str] = None, - attributes: Optional[Attributes] = None, - ) -> EventLogger: - return NoOpEventLogger( - name, version=version, schema_url=schema_url, attributes=attributes - ) - - -class ProxyEventLoggerProvider(EventLoggerProvider): - def get_event_logger( - self, - name: str, - version: Optional[str] = None, - schema_url: Optional[str] = None, - attributes: Optional[Attributes] = None, - ) -> EventLogger: - if _EVENT_LOGGER_PROVIDER: - return _EVENT_LOGGER_PROVIDER.get_event_logger( - name, - version=version, - schema_url=schema_url, - attributes=attributes, - ) - return ProxyEventLogger( - name, - version=version, - schema_url=schema_url, - attributes=attributes, - ) - - -_EVENT_LOGGER_PROVIDER_SET_ONCE = Once() -_EVENT_LOGGER_PROVIDER: Optional[EventLoggerProvider] = None -_PROXY_EVENT_LOGGER_PROVIDER = ProxyEventLoggerProvider() - - -def get_event_logger_provider() -> EventLoggerProvider: - global _EVENT_LOGGER_PROVIDER # pylint: disable=global-variable-not-assigned - if _EVENT_LOGGER_PROVIDER is None: - if _OTEL_PYTHON_EVENT_LOGGER_PROVIDER not in environ: - return _PROXY_EVENT_LOGGER_PROVIDER - - event_logger_provider: EventLoggerProvider = _load_provider( # type: ignore - _OTEL_PYTHON_EVENT_LOGGER_PROVIDER, "event_logger_provider" - ) - - _set_event_logger_provider(event_logger_provider, log=False) - - return cast("EventLoggerProvider", _EVENT_LOGGER_PROVIDER) - - -def _set_event_logger_provider( - event_logger_provider: EventLoggerProvider, log: bool -) -> None: - def set_elp() -> None: - global _EVENT_LOGGER_PROVIDER # pylint: disable=global-statement - _EVENT_LOGGER_PROVIDER = event_logger_provider - - did_set = _EVENT_LOGGER_PROVIDER_SET_ONCE.do_once(set_elp) - - if log and not did_set: - _logger.warning( - "Overriding of current EventLoggerProvider is not allowed" - ) - - -def set_event_logger_provider( - event_logger_provider: EventLoggerProvider, -) -> None: - _set_event_logger_provider(event_logger_provider, log=True) - - -def get_event_logger( - name: str, - version: Optional[str] = None, - schema_url: Optional[str] = None, - attributes: Optional[Attributes] = None, - event_logger_provider: Optional[EventLoggerProvider] = None, -) -> "EventLogger": - if event_logger_provider is None: - event_logger_provider = get_event_logger_provider() - return event_logger_provider.get_event_logger( - name, - version, - schema_url, - attributes, - ) diff --git a/opentelemetry-api/src/opentelemetry/_events/py.typed b/opentelemetry-api/src/opentelemetry/_events/py.typed deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/opentelemetry-api/src/opentelemetry/_logs/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/__init__.py index aaf29e5fe63..e3a7212cb56 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/__init__.py @@ -36,7 +36,6 @@ from opentelemetry._logs._internal import ( Logger, LoggerProvider, - LogRecord, NoOpLogger, NoOpLoggerProvider, get_logger, @@ -48,7 +47,6 @@ __all__ = [ "Logger", "LoggerProvider", - "LogRecord", "NoOpLogger", "NoOpLoggerProvider", "get_logger", diff --git a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py index f20bd8507e5..dd49797e803 100644 --- a/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_logs/_internal/__init__.py @@ -36,12 +36,11 @@ from abc import ABC, abstractmethod from logging import getLogger from os import environ -from time import time_ns from typing import Any, Optional, cast from opentelemetry._logs.severity import SeverityNumber +from opentelemetry.context.context import Context from opentelemetry.environment_variables import _OTEL_PYTHON_LOGGER_PROVIDER -from opentelemetry.trace.span import TraceFlags from opentelemetry.util._once import Once from opentelemetry.util._providers import _load_provider from opentelemetry.util.types import Attributes @@ -49,41 +48,8 @@ _logger = getLogger(__name__) -class LogRecord(ABC): - """A LogRecord instance represents an event being logged. - - LogRecord instances are created and emitted via `Logger` - every time something is logged. They contain all the information - pertinent to the event being logged. - """ - - def __init__( - self, - timestamp: Optional[int] = None, - observed_timestamp: Optional[int] = None, - trace_id: Optional[int] = None, - span_id: Optional[int] = None, - trace_flags: Optional["TraceFlags"] = None, - severity_text: Optional[str] = None, - severity_number: Optional[SeverityNumber] = None, - body: Optional[Any] = None, - attributes: Optional["Attributes"] = None, - ): - self.timestamp = timestamp - if observed_timestamp is None: - observed_timestamp = time_ns() - self.observed_timestamp = observed_timestamp - self.trace_id = trace_id - self.span_id = span_id - self.trace_flags = trace_flags - self.severity_text = severity_text - self.severity_number = severity_number - self.body = body # type: ignore - self.attributes = attributes - - class Logger(ABC): - """Handles emitting events and logs via `LogRecord`.""" + """Handles emitting events and logs.""" def __init__( self, @@ -99,8 +65,26 @@ def __init__( self._attributes = attributes @abstractmethod - def emit(self, record: "LogRecord") -> None: - """Emits a :class:`LogRecord` representing a log to the processing pipeline.""" + def is_enabled( + self, + severity_number: Optional[SeverityNumber] = None, + context: Optional[Context] = None, + ) -> bool: + """Returns True if the logger is enabled for given severity and context, False otherwise.""" + + @abstractmethod + def emit( + self, + event_name: str = None, + timestamp: Optional[int] = None, + observed_timestamp: Optional[int] = None, + severity_number: Optional[SeverityNumber] = None, + severity_text: Optional[str] = None, + context: Optional[Context] = None, + body: Optional[Any] = None, + attributes: Optional[Attributes] = None, + ) -> None: + """Emits a log record.""" class NoOpLogger(Logger): @@ -109,7 +93,24 @@ class NoOpLogger(Logger): All operations are no-op. """ - def emit(self, record: "LogRecord") -> None: + def is_enabled( + self, + severity_number: Optional[SeverityNumber] = None, + context: Optional[Context] = None, + ) -> bool: + return False + + def emit( + self, + event_name: str = None, + timestamp: Optional[int] = None, + observed_timestamp: Optional[int] = None, + severity_number: Optional[SeverityNumber] = None, + severity_text: Optional[str] = None, + context: Optional[Context] = None, + body: Optional[Any] = None, + attributes: Optional[Attributes] = None, + ) -> None: pass @@ -143,8 +144,36 @@ def _logger(self) -> Logger: return self._real_logger return self._noop_logger - def emit(self, record: LogRecord) -> None: - self._logger.emit(record) + def is_enabled( + self, + severity_number: Optional[SeverityNumber] = None, + context: Optional[Context] = None, + ) -> bool: + return self._logger.is_enabled( + severity_number=severity_number, context=context + ) + + def emit( + self, + event_name: str = None, + timestamp: Optional[int] = None, + observed_timestamp: Optional[int] = None, + severity_number: Optional[SeverityNumber] = None, + severity_text: Optional[str] = None, + context: Optional[Context] = None, + body: Optional[Any] = None, + attributes: Optional[Attributes] = None, + ) -> None: + self._logger.emit( + event_name=event_name, + timestamp=timestamp, + observed_timestamp=observed_timestamp, + severity_number=severity_number, + severity_text=severity_text, + context=context, + body=body, + attributes=attributes, + ) class LoggerProvider(ABC): diff --git a/opentelemetry-api/tests/events/test_event.py b/opentelemetry-api/tests/events/test_event.py deleted file mode 100644 index 227dcf5b1ff..00000000000 --- a/opentelemetry-api/tests/events/test_event.py +++ /dev/null @@ -1,21 +0,0 @@ -import unittest - -from opentelemetry._events import Event - - -class TestEvent(unittest.TestCase): - def test_event(self): - event = Event("example", 123, attributes={"key": "value"}) - self.assertEqual(event.name, "example") - self.assertEqual(event.timestamp, 123) - self.assertEqual( - event.attributes, {"key": "value", "event.name": "example"} - ) - - def test_event_name_copied_in_attributes(self): - event = Event("name", 123) - self.assertEqual(event.attributes, {"event.name": "name"}) - - def test_event_name_has_precedence_over_attributes(self): - event = Event("name", 123, attributes={"event.name": "attr value"}) - self.assertEqual(event.attributes, {"event.name": "name"}) diff --git a/opentelemetry-api/tests/events/test_event_logger_provider.py b/opentelemetry-api/tests/events/test_event_logger_provider.py deleted file mode 100644 index 425697bfa39..00000000000 --- a/opentelemetry-api/tests/events/test_event_logger_provider.py +++ /dev/null @@ -1,61 +0,0 @@ -# type:ignore -import unittest -from unittest.mock import Mock, patch - -import opentelemetry._events as events -from opentelemetry._events import ( - get_event_logger_provider, - set_event_logger_provider, -) -from opentelemetry.test.globals_test import EventsGlobalsTest - - -class TestGlobals(EventsGlobalsTest, unittest.TestCase): - @patch("opentelemetry._events._logger") - def test_set_event_logger_provider(self, logger_mock): - elp_mock = Mock() - # pylint: disable=protected-access - self.assertIsNone(events._EVENT_LOGGER_PROVIDER) - set_event_logger_provider(elp_mock) - self.assertIs(events._EVENT_LOGGER_PROVIDER, elp_mock) - self.assertIs(get_event_logger_provider(), elp_mock) - logger_mock.warning.assert_not_called() - - # pylint: disable=no-self-use - @patch("opentelemetry._events._logger") - def test_set_event_logger_provider_will_warn_second_call( - self, logger_mock - ): - elp_mock = Mock() - set_event_logger_provider(elp_mock) - set_event_logger_provider(elp_mock) - - logger_mock.warning.assert_called_once_with( - "Overriding of current EventLoggerProvider is not allowed" - ) - - def test_get_event_logger_provider(self): - # pylint: disable=protected-access - self.assertIsNone(events._EVENT_LOGGER_PROVIDER) - - self.assertIsInstance( - get_event_logger_provider(), events.ProxyEventLoggerProvider - ) - - events._EVENT_LOGGER_PROVIDER = None - - with patch.dict( - "os.environ", - { - "OTEL_PYTHON_EVENT_LOGGER_PROVIDER": "test_event_logger_provider" - }, - ): - with patch("opentelemetry._events._load_provider", Mock()): - with patch( - "opentelemetry._events.cast", - Mock(**{"return_value": "test_event_logger_provider"}), - ): - self.assertEqual( - get_event_logger_provider(), - "test_event_logger_provider", - ) diff --git a/opentelemetry-api/tests/events/test_proxy_event.py b/opentelemetry-api/tests/events/test_proxy_event.py deleted file mode 100644 index 736dcf35d60..00000000000 --- a/opentelemetry-api/tests/events/test_proxy_event.py +++ /dev/null @@ -1,50 +0,0 @@ -# pylint: disable=W0212,W0222,W0221 -import typing -import unittest - -import opentelemetry._events as events -from opentelemetry.test.globals_test import EventsGlobalsTest -from opentelemetry.util.types import Attributes - - -class TestProvider(events.NoOpEventLoggerProvider): - def get_event_logger( - self, - name: str, - version: typing.Optional[str] = None, - schema_url: typing.Optional[str] = None, - attributes: typing.Optional[Attributes] = None, - ) -> events.EventLogger: - return LoggerTest(name) - - -class LoggerTest(events.NoOpEventLogger): - def emit(self, event: events.Event) -> None: - pass - - -class TestProxy(EventsGlobalsTest, unittest.TestCase): - def test_proxy_logger(self): - provider = events.get_event_logger_provider() - # proxy provider - self.assertIsInstance(provider, events.ProxyEventLoggerProvider) - - # provider returns proxy logger - event_logger = provider.get_event_logger("proxy-test") - self.assertIsInstance(event_logger, events.ProxyEventLogger) - - # set a real provider - events.set_event_logger_provider(TestProvider()) - - # get_logger_provider() now returns the real provider - self.assertIsInstance(events.get_event_logger_provider(), TestProvider) - - # logger provider now returns real instance - self.assertIsInstance( - events.get_event_logger_provider().get_event_logger("fresh"), - LoggerTest, - ) - - # references to the old provider still work but return real logger now - real_logger = provider.get_event_logger("proxy-test") - self.assertIsInstance(real_logger, LoggerTest) diff --git a/opentelemetry-api/tests/logs/test_log_record.py b/opentelemetry-api/tests/logs/test_log_record.py deleted file mode 100644 index a06ed8dabfc..00000000000 --- a/opentelemetry-api/tests/logs/test_log_record.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import unittest -from unittest.mock import patch - -from opentelemetry._logs import LogRecord - -OBSERVED_TIMESTAMP = "OBSERVED_TIMESTAMP" - - -class TestLogRecord(unittest.TestCase): - @patch("opentelemetry._logs._internal.time_ns") - def test_log_record_observed_timestamp_default(self, time_ns_mock): # type: ignore - time_ns_mock.return_value = OBSERVED_TIMESTAMP - self.assertEqual(LogRecord().observed_timestamp, OBSERVED_TIMESTAMP) diff --git a/opentelemetry-api/tests/logs/test_proxy.py b/opentelemetry-api/tests/logs/test_proxy.py index 8e87ceb96ea..d6e344e65b9 100644 --- a/opentelemetry-api/tests/logs/test_proxy.py +++ b/opentelemetry-api/tests/logs/test_proxy.py @@ -18,6 +18,7 @@ import opentelemetry._logs._internal as _logs_internal from opentelemetry import _logs +from opentelemetry.context.context import Context from opentelemetry.test.globals_test import LoggingGlobalsTest from opentelemetry.util.types import Attributes @@ -34,7 +35,17 @@ def get_logger( class LoggerTest(_logs.NoOpLogger): - def emit(self, record: _logs.LogRecord) -> None: + def emit( + self, + event_name: str = None, + timestamp: typing.Optional[int] = None, + observed_timestamp: typing.Optional[int] = None, + severity_number: typing.Optional[_logs.SeverityNumber] = None, + severity_text: typing.Optional[str] = None, + context: typing.Optional[Context] = None, + body: typing.Optional[typing.Any] = None, + attributes: typing.Optional[Attributes] = None, + ) -> None: pass diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 2dffd780236..8cc15d3bf49 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -25,7 +25,6 @@ from typing_extensions import Literal -from opentelemetry._events import set_event_logger_provider from opentelemetry._logs import set_logger_provider from opentelemetry.environment_variables import ( OTEL_LOGS_EXPORTER, @@ -34,7 +33,6 @@ OTEL_TRACES_EXPORTER, ) from opentelemetry.metrics import set_meter_provider -from opentelemetry.sdk._events import EventLoggerProvider from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, LogExporter from opentelemetry.sdk.environment_variables import ( @@ -250,9 +248,6 @@ def _init_logging( logging.getLogger().addHandler(handler) - event_logger_provider = EventLoggerProvider(logger_provider=provider) - set_event_logger_provider(event_logger_provider) - def _import_exporters( trace_exporter_names: Sequence[str], diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_events/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_events/__init__.py deleted file mode 100644 index ae16302546d..00000000000 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_events/__init__.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import logging -from time import time_ns -from typing import Optional - -from opentelemetry import trace -from opentelemetry._events import Event -from opentelemetry._events import EventLogger as APIEventLogger -from opentelemetry._events import EventLoggerProvider as APIEventLoggerProvider -from opentelemetry._logs import NoOpLogger, SeverityNumber, get_logger_provider -from opentelemetry.sdk._logs import Logger, LoggerProvider, LogRecord -from opentelemetry.util.types import Attributes - -_logger = logging.getLogger(__name__) - - -class EventLogger(APIEventLogger): - def __init__( - self, - logger_provider: LoggerProvider, - name: str, - version: Optional[str] = None, - schema_url: Optional[str] = None, - attributes: Optional[Attributes] = None, - ): - super().__init__( - name=name, - version=version, - schema_url=schema_url, - attributes=attributes, - ) - self._logger: Logger = logger_provider.get_logger( - name, version, schema_url, attributes - ) - - def emit(self, event: Event) -> None: - if isinstance(self._logger, NoOpLogger): - # Do nothing if SDK is disabled - return - span_context = trace.get_current_span().get_span_context() - log_record = LogRecord( - timestamp=event.timestamp or time_ns(), - observed_timestamp=None, - trace_id=event.trace_id or span_context.trace_id, - span_id=event.span_id or span_context.span_id, - trace_flags=event.trace_flags or span_context.trace_flags, - severity_text=None, - severity_number=event.severity_number or SeverityNumber.INFO, - body=event.body, - resource=getattr(self._logger, "resource", None), - attributes=event.attributes, - ) - self._logger.emit(log_record) - - -class EventLoggerProvider(APIEventLoggerProvider): - def __init__(self, logger_provider: Optional[LoggerProvider] = None): - self._logger_provider = logger_provider or get_logger_provider() - - def get_event_logger( - self, - name: str, - version: Optional[str] = None, - schema_url: Optional[str] = None, - attributes: Optional[Attributes] = None, - ) -> EventLogger: - if not name: - _logger.warning("EventLogger created with invalid name: %s", name) - return EventLogger( - self._logger_provider, name, version, schema_url, attributes - ) - - def shutdown(self): - self._logger_provider.shutdown() - - def force_flush(self, timeout_millis: int = 30000) -> bool: - self._logger_provider.force_flush(timeout_millis) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py index 0254c135e84..f9c8c218110 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/__init__.py @@ -14,7 +14,6 @@ from opentelemetry.sdk._logs._internal import ( - LogData, LogDroppedAttributesWarning, Logger, LoggerProvider, @@ -25,7 +24,6 @@ ) __all__ = [ - "LogData", "Logger", "LoggerProvider", "LoggingHandler", diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py index c2db81687a2..6096b8683c6 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py @@ -27,7 +27,6 @@ from opentelemetry._logs import Logger as APILogger from opentelemetry._logs import LoggerProvider as APILoggerProvider -from opentelemetry._logs import LogRecord as APILogRecord from opentelemetry._logs import ( NoOpLogger, SeverityNumber, @@ -36,6 +35,7 @@ std_to_otel, ) from opentelemetry.attributes import BoundedAttributes +from opentelemetry.context.context import Context from opentelemetry.sdk.environment_variables import ( OTEL_ATTRIBUTE_COUNT_LIMIT, OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT, @@ -53,8 +53,6 @@ from opentelemetry.trace.span import TraceFlags from opentelemetry.util.types import AnyValue, Attributes -_logger = logging.getLogger(__name__) - _DEFAULT_OTEL_ATTRIBUTE_COUNT_LIMIT = 128 _ENV_VALUE_UNSET = "" @@ -162,7 +160,7 @@ def _from_env_if_absent( ) -class LogRecord(APILogRecord): +class LogRecord: """A LogRecord instance represents an event being logged. LogRecord instances are created and emitted via `Logger` @@ -172,6 +170,7 @@ class LogRecord(APILogRecord): def __init__( self, + event_name: Optional[str] = None, timestamp: Optional[int] = None, observed_timestamp: Optional[int] = None, trace_id: Optional[int] = None, @@ -183,28 +182,31 @@ def __init__( resource: Optional[Resource] = None, attributes: Optional[Attributes] = None, limits: Optional[LogLimits] = _UnsetLogLimits, + instrumentation_scope: Optional[InstrumentationScope] = None, ): - super().__init__( - **{ - "timestamp": timestamp, - "observed_timestamp": observed_timestamp, - "trace_id": trace_id, - "span_id": span_id, - "trace_flags": trace_flags, - "severity_text": severity_text, - "severity_number": severity_number, - "body": body, - "attributes": BoundedAttributes( - maxlen=limits.max_attributes, - attributes=attributes if bool(attributes) else None, - immutable=False, - max_value_len=limits.max_attribute_length, - ), - } + self.event_name = event_name + self.timestamp = timestamp + self.observed_timestamp = ( + observed_timestamp if observed_timestamp is not None else time_ns() + ) + self.trace_id = trace_id + self.span_id = span_id + self.trace_flags = trace_flags + self.severity_text = severity_text + self.severity_number = severity_number + self.body = body + self.instrumentation_scope = instrumentation_scope + self.attributes = BoundedAttributes( + maxlen=limits.max_attributes, + attributes=attributes if bool(attributes) else None, + immutable=False, + max_value_len=limits.max_attribute_length, ) + self.resource = ( resource if isinstance(resource, Resource) else Resource.create({}) ) + if self.dropped_attributes > 0: warnings.warn( "Log record attributes were dropped due to limits", @@ -220,6 +222,7 @@ def __eq__(self, other: object) -> bool: def to_json(self, indent=4) -> str: return json.dumps( { + "event_name": self.event_name, "body": self.body, "severity_number": self.severity_number.value if self.severity_number is not None @@ -243,6 +246,9 @@ def to_json(self, indent=4) -> str: ), "trace_flags": self.trace_flags, "resource": json.loads(self.resource.to_json()), + "instrumentation_scope": json.loads( + self.instrumentation_scope.to_json() + ), }, indent=indent, ) @@ -254,18 +260,6 @@ def dropped_attributes(self) -> int: return 0 -class LogData: - """Readable LogRecord data plus associated InstrumentationLibrary.""" - - def __init__( - self, - log_record: LogRecord, - instrumentation_scope: InstrumentationScope, - ): - self.log_record = log_record - self.instrumentation_scope = instrumentation_scope - - class LogRecordProcessor(abc.ABC): """Interface to hook the log record emitting action. @@ -275,8 +269,8 @@ class LogRecordProcessor(abc.ABC): """ @abc.abstractmethod - def emit(self, log_data: LogData): - """Emits the `LogData`""" + def emit(self, log_data: LogRecord): + """Emits the `LogRecord`""" @abc.abstractmethod def shutdown(self): @@ -319,9 +313,9 @@ def add_log_record_processor( with self._lock: self._log_record_processors += (log_record_processor,) - def emit(self, log_data: LogData) -> None: + def emit(self, log_record: LogRecord) -> None: for lp in self._log_record_processors: - lp.emit(log_data) + lp.emit(log_record) def shutdown(self) -> None: """Shutdown the log processors one by one""" @@ -393,8 +387,8 @@ def _submit_and_wait( for future in futures: future.result() - def emit(self, log_data: LogData): - self._submit_and_wait(lambda lp: lp.emit, log_data) + def emit(self, log_record: LogRecord): + self._submit_and_wait(lambda lp: lp.emit, log_record) def shutdown(self): self._submit_and_wait(lambda lp: lp.shutdown) @@ -501,10 +495,10 @@ def _get_attributes(record: logging.LogRecord) -> Attributes: ) return attributes - def _translate(self, record: logging.LogRecord) -> LogRecord: + def _translate_and_emit( + self, logger: APILogger, record: logging.LogRecord + ) -> LogRecord: timestamp = int(record.created * 1e9) - observered_timestamp = time_ns() - span_context = get_current_span().get_span_context() attributes = self._get_attributes(record) severity_number = std_to_otel(record.levelno) if self.formatter: @@ -533,17 +527,11 @@ def _translate(self, record: logging.LogRecord) -> LogRecord: "WARN" if record.levelname == "WARNING" else record.levelname ) - logger = get_logger(record.name, logger_provider=self._logger_provider) - return LogRecord( + logger.emit( timestamp=timestamp, - observed_timestamp=observered_timestamp, - trace_id=span_context.trace_id, - span_id=span_context.span_id, - trace_flags=span_context.trace_flags, severity_text=level_name, severity_number=severity_number, body=body, - resource=logger.resource, attributes=attributes, ) @@ -555,7 +543,7 @@ def emit(self, record: logging.LogRecord) -> None: """ logger = get_logger(record.name, logger_provider=self._logger_provider) if not isinstance(logger, NoOpLogger): - logger.emit(self._translate(record)) + self._translate_and_emit(logger, record) def flush(self) -> None: """ @@ -591,12 +579,43 @@ def __init__( def resource(self): return self._resource - def emit(self, record: LogRecord): - """Emits the :class:`LogData` by associating :class:`LogRecord` - and instrumentation info. - """ - log_data = LogData(record, self._instrumentation_scope) - self._multi_log_record_processor.emit(log_data) + def is_enabled( + self, + severity_number: Optional[SeverityNumber] = None, + context: Optional[Context] = None, + ) -> bool: + """Returns True if the logger is enabled for given severity and context, False otherwise.""" + return True # TODO + + def emit( + self, + event_name: str = None, + timestamp: Optional[int] = None, + observed_timestamp: Optional[int] = None, + severity_number: Optional[SeverityNumber] = None, + severity_text: Optional[str] = None, + context: Optional[Context] = None, + body: Optional[Any] = None, + attributes: Optional[Attributes] = None, + ): + """Emits the :class:`LogRecord`.""" + + span_context = get_current_span(context).get_span_context() + log_record = LogRecord( + event_name=event_name, + timestamp=timestamp, + observed_timestamp=observed_timestamp, + severity_number=severity_number, + severity_text=severity_text, + trace_id=span_context.trace_id, + span_id=span_context.span_id, + trace_flags=span_context.trace_flags, + body=body, + attributes=attributes, + resource=self._resource, + instrumentation_scope=self._instrumentation_scope, + ) + self._multi_log_record_processor.emit(log_record) class LoggerProvider(APILoggerProvider): diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/__init__.py index e5669580c4b..b7b4c210cbb 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/__init__.py @@ -29,7 +29,7 @@ detach, set_value, ) -from opentelemetry.sdk._logs import LogData, LogRecord, LogRecordProcessor +from opentelemetry.sdk._logs import LogRecord, LogRecordProcessor from opentelemetry.sdk.environment_variables import ( OTEL_BLRP_EXPORT_TIMEOUT, OTEL_BLRP_MAX_EXPORT_BATCH_SIZE, @@ -65,11 +65,11 @@ class LogExporter(abc.ABC): """ @abc.abstractmethod - def export(self, batch: Sequence[LogData]): + def export(self, batch: Sequence[LogRecord]): """Exports a batch of logs. Args: - batch: The list of `LogData` objects to be exported + batch: The list of `LogRecord` objects to be exported Returns: The result of the export @@ -100,9 +100,9 @@ def __init__( self.out = out self.formatter = formatter - def export(self, batch: Sequence[LogData]): - for data in batch: - self.out.write(self.formatter(data.log_record)) + def export(self, batch: Sequence[LogRecord]): + for log_record in batch: + self.out.write(self.formatter(log_record)) self.out.flush() return LogExportResult.SUCCESS @@ -112,7 +112,7 @@ def shutdown(self): class SimpleLogRecordProcessor(LogRecordProcessor): """This is an implementation of LogRecordProcessor which passes - received logs in the export-friendly LogData representation to the + received logs in the export-friendly LogRecord representation to the configured LogExporter, as soon as they are emitted. """ @@ -120,13 +120,13 @@ def __init__(self, exporter: LogExporter): self._exporter = exporter self._shutdown = False - def emit(self, log_data: LogData): + def emit(self, log_record: LogRecord): if self._shutdown: _logger.warning("Processor is already shutdown, ignoring call") return token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)) try: - self._exporter.export((log_data,)) + self._exporter.export((log_record,)) except Exception: # pylint: disable=broad-exception-caught _logger.exception("Exception while exporting logs.") detach(token) @@ -152,7 +152,7 @@ def __init__(self): class BatchLogRecordProcessor(LogRecordProcessor): """This is an implementation of LogRecordProcessor which creates batches of - received logs in the export-friendly LogData representation and + received logs in the export-friendly LogRecord representation and send to the configured LogExporter, as soon as they are emitted. `BatchLogRecordProcessor` is configurable with the following environment @@ -164,9 +164,9 @@ class BatchLogRecordProcessor(LogRecordProcessor): - :envvar:`OTEL_BLRP_EXPORT_TIMEOUT` """ - _queue: Deque[LogData] + _queue: Deque[LogRecord] _flush_request: Optional[_FlushRequest] - _log_records: List[Optional[LogData]] + _log_records: List[Optional[LogRecord]] def __init__( self, @@ -341,8 +341,8 @@ def _get_or_create_flush_request(self) -> _FlushRequest: self._flush_request = _FlushRequest() return self._flush_request - def emit(self, log_data: LogData) -> None: - """Adds the `LogData` to queue and notifies the waiting threads + def emit(self, log_data: LogRecord) -> None: + """Adds the `LogRecord` to queue and notifies the waiting threads when size of queue reaches max_export_batch_size. """ if self._shutdown: diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/in_memory_log_exporter.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/in_memory_log_exporter.py index 68cb6b7389a..b4e0239c246 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/in_memory_log_exporter.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/export/in_memory_log_exporter.py @@ -15,7 +15,7 @@ import threading import typing -from opentelemetry.sdk._logs import LogData +from opentelemetry.sdk._logs import LogRecord from opentelemetry.sdk._logs.export import LogExporter, LogExportResult @@ -36,11 +36,11 @@ def clear(self) -> None: with self._lock: self._logs.clear() - def get_finished_logs(self) -> typing.Tuple[LogData, ...]: + def get_finished_logs(self) -> typing.Tuple[LogRecord, ...]: with self._lock: return tuple(self._logs) - def export(self, batch: typing.Sequence[LogData]) -> LogExportResult: + def export(self, batch: typing.Sequence[LogRecord]) -> LogExportResult: if self._stopped: return LogExportResult.FAILURE with self._lock: diff --git a/opentelemetry-sdk/tests/events/test_events.py b/opentelemetry-sdk/tests/events/test_events.py deleted file mode 100644 index 7b8d42ff316..00000000000 --- a/opentelemetry-sdk/tests/events/test_events.py +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# pylint: disable=protected-access,no-self-use - -import unittest -from unittest.mock import Mock, patch - -from opentelemetry._events import Event -from opentelemetry._logs import SeverityNumber, set_logger_provider -from opentelemetry.sdk._events import EventLoggerProvider -from opentelemetry.sdk._logs import LoggerProvider -from opentelemetry.sdk._logs._internal import Logger, NoOpLogger -from opentelemetry.sdk.environment_variables import OTEL_SDK_DISABLED - - -class TestEventLoggerProvider(unittest.TestCase): - def test_event_logger_provider(self): - logger_provider = LoggerProvider() - event_logger_provider = EventLoggerProvider( - logger_provider=logger_provider - ) - - self.assertEqual( - event_logger_provider._logger_provider, - logger_provider, - ) - - def test_event_logger_provider_default(self): - logger_provider = LoggerProvider() - set_logger_provider(logger_provider) - event_logger_provider = EventLoggerProvider() - - self.assertEqual( - event_logger_provider._logger_provider, - logger_provider, - ) - - def test_get_event_logger(self): - logger_provider = LoggerProvider() - event_logger = EventLoggerProvider(logger_provider).get_event_logger( - "name", - version="version", - schema_url="schema_url", - attributes={"key": "value"}, - ) - self.assertTrue( - event_logger._logger, - Logger, - ) - logger = event_logger._logger - self.assertEqual(logger._instrumentation_scope.name, "name") - self.assertEqual(logger._instrumentation_scope.version, "version") - self.assertEqual( - logger._instrumentation_scope.schema_url, "schema_url" - ) - self.assertEqual( - logger._instrumentation_scope.attributes, {"key": "value"} - ) - - @patch.dict("os.environ", {OTEL_SDK_DISABLED: "true"}) - def test_get_event_logger_with_sdk_disabled(self): - logger_provider = LoggerProvider() - event_logger = EventLoggerProvider(logger_provider).get_event_logger( - "name", - version="version", - schema_url="schema_url", - attributes={"key": "value"}, - ) - self.assertIsInstance(event_logger._logger, NoOpLogger) - - def test_force_flush(self): - logger_provider = Mock() - event_logger = EventLoggerProvider(logger_provider) - event_logger.force_flush(1000) - logger_provider.force_flush.assert_called_once_with(1000) - - def test_shutdown(self): - logger_provider = Mock() - event_logger = EventLoggerProvider(logger_provider) - event_logger.shutdown() - logger_provider.shutdown.assert_called_once() - - @patch("opentelemetry.sdk._logs._internal.LoggerProvider.get_logger") - def test_event_logger(self, logger_mock): - logger_provider = LoggerProvider() - logger_mock_inst = Mock() - logger_mock.return_value = logger_mock_inst - EventLoggerProvider(logger_provider).get_event_logger( - "name", - version="version", - schema_url="schema_url", - attributes={"key": "value"}, - ) - logger_mock.assert_called_once_with( - "name", "version", "schema_url", {"key": "value"} - ) - - @patch("opentelemetry.sdk._events.LogRecord") - @patch("opentelemetry.sdk._logs._internal.LoggerProvider.get_logger") - def test_event_logger_emit(self, logger_mock, log_record_mock): - logger_provider = LoggerProvider() - logger_mock_inst = Mock() - logger_mock.return_value = logger_mock_inst - event_logger = EventLoggerProvider(logger_provider).get_event_logger( - "name", - version="version", - schema_url="schema_url", - attributes={"key": "value"}, - ) - logger_mock.assert_called_once_with( - "name", "version", "schema_url", {"key": "value"} - ) - now = Mock() - trace_id = Mock() - span_id = Mock() - trace_flags = Mock() - event = Event( - name="test_event", - timestamp=now, - trace_id=trace_id, - span_id=span_id, - trace_flags=trace_flags, - body="test body", - severity_number=SeverityNumber.ERROR, - attributes={ - "key": "val", - "foo": "bar", - "event.name": "not this one", - }, - ) - log_record_mock_inst = Mock() - log_record_mock.return_value = log_record_mock_inst - event_logger.emit(event) - log_record_mock.assert_called_once_with( - timestamp=now, - observed_timestamp=None, - trace_id=trace_id, - span_id=span_id, - trace_flags=trace_flags, - severity_text=None, - severity_number=SeverityNumber.ERROR, - body="test body", - resource=event_logger._logger.resource, - attributes={ - "key": "val", - "foo": "bar", - "event.name": "test_event", - }, - ) - logger_mock_inst.emit.assert_called_once_with(log_record_mock_inst) - - @patch("opentelemetry.sdk._events.LogRecord") - @patch("opentelemetry.sdk._logs._internal.LoggerProvider.get_logger") - def test_event_logger_emit_sdk_disabled( - self, logger_mock, log_record_mock - ): - logger_provider = LoggerProvider() - logger_mock_inst = Mock(spec=NoOpLogger) - logger_mock.return_value = logger_mock_inst - event_logger = EventLoggerProvider(logger_provider).get_event_logger( - "name", - version="version", - schema_url="schema_url", - attributes={"key": "value"}, - ) - logger_mock.assert_called_once_with( - "name", "version", "schema_url", {"key": "value"} - ) - now = Mock() - trace_id = Mock() - span_id = Mock() - trace_flags = Mock() - event = Event( - name="test_event", - timestamp=now, - trace_id=trace_id, - span_id=span_id, - trace_flags=trace_flags, - body="test body", - severity_number=SeverityNumber.ERROR, - attributes={ - "key": "val", - "foo": "bar", - "event.name": "not this one", - }, - ) - log_record_mock_inst = Mock() - log_record_mock.return_value = log_record_mock_inst - event_logger.emit(event) - logger_mock_inst.emit.assert_not_called() diff --git a/opentelemetry-sdk/tests/logs/test_export.py b/opentelemetry-sdk/tests/logs/test_export.py index 2e00bad6538..f322459e241 100644 --- a/opentelemetry-sdk/tests/logs/test_export.py +++ b/opentelemetry-sdk/tests/logs/test_export.py @@ -24,7 +24,6 @@ from opentelemetry._logs import SeverityNumber from opentelemetry.sdk import trace from opentelemetry.sdk._logs import ( - LogData, LoggerProvider, LoggingHandler, LogRecord, @@ -65,7 +64,7 @@ def test_simple_log_record_processor_default_level(self): logger.warning("Something is wrong") finished_logs = exporter.get_finished_logs() self.assertEqual(len(finished_logs), 1) - warning_log_record = finished_logs[0].log_record + warning_log_record = finished_logs[0] self.assertEqual(warning_log_record.body, "Something is wrong") self.assertEqual(warning_log_record.severity_text, "WARN") self.assertEqual( @@ -95,8 +94,8 @@ def test_simple_log_record_processor_custom_level(self): finished_logs = exporter.get_finished_logs() # Make sure only level >= logging.CRITICAL logs are recorded self.assertEqual(len(finished_logs), 2) - critical_log_record = finished_logs[0].log_record - fatal_log_record = finished_logs[1].log_record + critical_log_record = finished_logs[0] + fatal_log_record = finished_logs[1] self.assertEqual(critical_log_record.body, "Error message") self.assertEqual(critical_log_record.severity_text, "ERROR") self.assertEqual( @@ -129,7 +128,7 @@ def test_simple_log_record_processor_trace_correlation(self): logger.warning("Warning message") finished_logs = exporter.get_finished_logs() self.assertEqual(len(finished_logs), 1) - log_record = finished_logs[0].log_record + log_record = finished_logs[0] self.assertEqual(log_record.body, "Warning message") self.assertEqual(log_record.severity_text, "WARN") self.assertEqual(log_record.severity_number, SeverityNumber.WARN) @@ -148,7 +147,7 @@ def test_simple_log_record_processor_trace_correlation(self): logger.critical("Critical message within span") finished_logs = exporter.get_finished_logs() - log_record = finished_logs[0].log_record + log_record = finished_logs[0] self.assertEqual(log_record.body, "Critical message within span") self.assertEqual(log_record.severity_text, "CRITICAL") self.assertEqual(log_record.severity_number, SeverityNumber.FATAL) @@ -176,7 +175,7 @@ def test_simple_log_record_processor_shutdown(self): logger.warning("Something is wrong") finished_logs = exporter.get_finished_logs() self.assertEqual(len(finished_logs), 1) - warning_log_record = finished_logs[0].log_record + warning_log_record = finished_logs[0] self.assertEqual(warning_log_record.body, "Something is wrong") self.assertEqual(warning_log_record.severity_text, "WARN") self.assertEqual( @@ -220,10 +219,7 @@ def test_simple_log_record_processor_different_msg_types(self): (["list", "of", "strings"], "WARN"), ({"key": "value"}, "ERROR"), ] - emitted = [ - (item.log_record.body, item.log_record.severity_text) - for item in finished_logs - ] + emitted = [(item.body, item.severity_text) for item in finished_logs] self.assertEqual(expected, emitted) for item in finished_logs: self.assertEqual( @@ -273,7 +269,7 @@ def test_simple_log_record_processor_custom_single_obj(self): (["a non-string with a percent-s", "%s"]), ] for emitted, expected in zip(finished_logs, expected): - self.assertEqual(emitted.log_record.body, expected) + self.assertEqual(emitted.body, expected) self.assertEqual(emitted.instrumentation_scope.name, "single_obj") def test_simple_log_record_processor_different_msg_types_with_formatter( @@ -319,10 +315,7 @@ def test_simple_log_record_processor_different_msg_types_with_formatter( ), ("different_msg_types - ERROR - {'key': 'value'}", "ERROR"), ] - emitted = [ - (item.log_record.body, item.log_record.severity_text) - for item in finished_logs - ] + emitted = [(item.body, item.severity_text) for item in finished_logs] self.assertEqual(expected, emitted) @@ -492,10 +485,7 @@ def test_shutdown(self): "CRITICAL", ), ] - emitted = [ - (item.log_record.body, item.log_record.severity_text) - for item in finished_logs - ] + emitted = [(item.body, item.severity_text) for item in finished_logs] self.assertEqual(expected, emitted) for item in finished_logs: self.assertEqual(item.instrumentation_scope.name, "shutdown") @@ -515,7 +505,7 @@ def test_force_flush(self): log_record_processor.force_flush() finished_logs = exporter.get_finished_logs() self.assertEqual(len(finished_logs), 1) - log_record = finished_logs[0].log_record + log_record = finished_logs[0] self.assertEqual(log_record.body, "Earth is burning") self.assertEqual(log_record.severity_number, SeverityNumber.FATAL) self.assertEqual( @@ -623,18 +613,16 @@ def _target(): class TestConsoleLogExporter(unittest.TestCase): def test_export(self): # pylint: disable=no-self-use """Check that the console exporter prints log records.""" - log_data = LogData( - log_record=LogRecord( - timestamp=int(time.time() * 1e9), - trace_id=2604504634922341076776623263868986797, - span_id=5213367945872657620, - trace_flags=TraceFlags(0x01), - severity_text="WARN", - severity_number=SeverityNumber.WARN, - body="Zhengzhou, We have a heaviest rains in 1000 years", - resource=SDKResource({"key": "value"}), - attributes={"a": 1, "b": "c"}, - ), + log_record = LogRecord( + timestamp=int(time.time() * 1e9), + trace_id=2604504634922341076776623263868986797, + span_id=5213367945872657620, + trace_flags=TraceFlags(0x01), + severity_text="WARN", + severity_number=SeverityNumber.WARN, + body="Zhengzhou, We have a heaviest rains in 1000 years", + resource=SDKResource({"key": "value"}), + attributes={"a": 1, "b": "c"}, instrumentation_scope=InstrumentationScope( "first_name", "first_version" ), @@ -644,9 +632,9 @@ def test_export(self): # pylint: disable=no-self-use # the exporter instance instead. with patch.object(exporter, "out") as mock_stdout: - exporter.export([log_data]) + exporter.export([log_record]) mock_stdout.write.assert_called_once_with( - log_data.log_record.to_json() + os.linesep + log_record.to_json() + os.linesep ) self.assertEqual(mock_stdout.write.call_count, 1) @@ -661,11 +649,10 @@ def formatter(record): # pylint: disable=unused-argument mock_stdout = Mock() exporter = ConsoleLogExporter(out=mock_stdout, formatter=formatter) - log_data = LogData( - log_record=LogRecord(), + log_record = LogRecord( instrumentation_scope=InstrumentationScope( "first_name", "first_version" ), ) - exporter.export([log_data]) + exporter.export([log_record]) mock_stdout.write.assert_called_once_with(mock_record_str) diff --git a/opentelemetry-sdk/tests/logs/test_handler.py b/opentelemetry-sdk/tests/logs/test_handler.py index f6daa1b22cf..56c786b8950 100644 --- a/opentelemetry-sdk/tests/logs/test_handler.py +++ b/opentelemetry-sdk/tests/logs/test_handler.py @@ -23,9 +23,9 @@ from opentelemetry.attributes import BoundedAttributes from opentelemetry.sdk import trace from opentelemetry.sdk._logs import ( - LogData, LoggerProvider, LoggingHandler, + LogRecord, LogRecordProcessor, ) from opentelemetry.semconv.trace import SpanAttributes @@ -315,8 +315,8 @@ class FakeProcessor(LogRecordProcessor): def __init__(self): self.log_data_emitted = [] - def emit(self, log_data: LogData): - self.log_data_emitted.append(log_data) + def emit(self, log_record: LogRecord): + self.log_data_emitted.append(log_record) def shutdown(self): pass @@ -328,4 +328,4 @@ def emit_count(self): return len(self.log_data_emitted) def get_log_record(self, i): - return self.log_data_emitted[i].log_record + return self.log_data_emitted[i] diff --git a/opentelemetry-sdk/tests/logs/test_log_record.py b/opentelemetry-sdk/tests/logs/test_log_record.py index f42d3a26ea4..6cc7db2980f 100644 --- a/opentelemetry-sdk/tests/logs/test_log_record.py +++ b/opentelemetry-sdk/tests/logs/test_log_record.py @@ -24,12 +24,14 @@ LogRecord, ) from opentelemetry.sdk.resources import Resource +from opentelemetry.sdk.util.instrumentation import InstrumentationScope class TestLogRecord(unittest.TestCase): def test_log_record_to_json(self): expected = json.dumps( { + "event_name": None, "body": "a log line", "severity_number": None, "severity_text": None, @@ -44,6 +46,12 @@ def test_log_record_to_json(self): "attributes": {"service.name": "foo"}, "schema_url": "", }, + "instrumentation_scope": { + "name": "name", + "version": "version", + "schema_url": "", + "attributes": None, + }, }, indent=4, ) @@ -52,12 +60,14 @@ def test_log_record_to_json(self): observed_timestamp=0, body="a log line", resource=Resource({"service.name": "foo"}), + instrumentation_scope=InstrumentationScope("name", "version"), ) self.assertEqual(expected, actual.to_json(indent=4)) + self.assertEqual( actual.to_json(indent=None), - '{"body": "a log line", "severity_number": null, "severity_text": null, "attributes": null, "dropped_attributes": 0, "timestamp": "1970-01-01T00:00:00.000000Z", "observed_timestamp": "1970-01-01T00:00:00.000000Z", "trace_id": "", "span_id": "", "trace_flags": null, "resource": {"attributes": {"service.name": "foo"}, "schema_url": ""}}', + '{"event_name": null, "body": "a log line", "severity_number": null, "severity_text": null, "attributes": null, "dropped_attributes": 0, "timestamp": "1970-01-01T00:00:00.000000Z", "observed_timestamp": "1970-01-01T00:00:00.000000Z", "trace_id": "", "span_id": "", "trace_flags": null, "resource": {"attributes": {"service.name": "foo"}, "schema_url": ""}, "instrumentation_scope": {"name": "name", "version": "version", "schema_url": "", "attributes": null}}', ) def test_log_record_to_json_serializes_severity_number_as_int(self): @@ -67,6 +77,7 @@ def test_log_record_to_json_serializes_severity_number_as_int(self): observed_timestamp=0, body="a log line", resource=Resource({"service.name": "foo"}), + instrumentation_scope=InstrumentationScope("name", "version"), ) decoded = json.loads(actual.to_json()) diff --git a/opentelemetry-sdk/tests/logs/test_multi_log_processor.py b/opentelemetry-sdk/tests/logs/test_multi_log_processor.py index 110fedb9578..f1cc1ec42aa 100644 --- a/opentelemetry-sdk/tests/logs/test_multi_log_processor.py +++ b/opentelemetry-sdk/tests/logs/test_multi_log_processor.py @@ -38,12 +38,10 @@ def __init__(self, exporter, logs_list): self._log_list = logs_list self._closed = False - def emit(self, log_data): + def emit(self, log_record): if self._closed: return - self._log_list.append( - (log_data.log_record.body, log_data.log_record.severity_text) - ) + self._log_list.append((log_record.body, log_record.severity_text)) def shutdown(self): self._closed = True diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 034d5b8c9be..43ed9cc2c08 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -16,13 +16,14 @@ from logging import WARNING, getLogger from os import environ -from typing import Dict, Iterable, Optional, Sequence +from typing import Any, Dict, Iterable, Optional, Sequence from unittest import TestCase from unittest.mock import Mock, patch from pytest import raises from opentelemetry import trace +from opentelemetry._logs import SeverityNumber from opentelemetry.context import Context from opentelemetry.environment_variables import OTEL_PYTHON_ID_GENERATOR from opentelemetry.sdk._configuration import ( @@ -42,7 +43,7 @@ _initialize_components, _OTelSDKConfigurator, ) -from opentelemetry.sdk._logs import LoggingHandler +from opentelemetry.sdk._logs import LoggingHandler, LogRecord from opentelemetry.sdk._logs.export import ConsoleLogExporter from opentelemetry.sdk.environment_variables import ( OTEL_TRACES_SAMPLER, @@ -109,8 +110,32 @@ def __init__(self, name, resource, processor): self.resource = resource self.processor = processor - def emit(self, record): - self.processor.emit(record) + def emit( + self, + event_name: str = None, + timestamp: Optional[int] = None, + observed_timestamp: Optional[int] = None, + severity_number: Optional[SeverityNumber] = None, + severity_text: Optional[str] = None, + context: Optional[Context] = None, + body: Optional[Any] = None, + attributes: Optional[Attributes] = None, + ): + span_context = trace.get_current_span(context).get_span_context() + self.processor.emit( + LogRecord( + event_name=event_name, + timestamp=timestamp, + observed_timestamp=observed_timestamp, + severity_number=severity_number, + severity_text=severity_text, + trace_id=span_context.trace_id, + span_id=span_context.span_id, + trace_flags=span_context.trace_flags, + body=body, + attributes=attributes, + ) + ) class DummyLogRecordProcessor: @@ -586,32 +611,14 @@ def setUp(self): "opentelemetry.sdk._configuration.set_logger_provider" ) - self.event_logger_provider_instance_mock = Mock() - self.event_logger_provider_patch = patch( - "opentelemetry.sdk._configuration.EventLoggerProvider", - return_value=self.event_logger_provider_instance_mock, - ) - self.set_event_logger_provider_patch = patch( - "opentelemetry.sdk._configuration.set_event_logger_provider" - ) - self.processor_mock = self.processor_patch.start() self.provider_mock = self.provider_patch.start() self.set_provider_mock = self.set_provider_patch.start() - self.event_logger_provider_mock = ( - self.event_logger_provider_patch.start() - ) - self.set_event_logger_provider_mock = ( - self.set_event_logger_provider_patch.start() - ) - def tearDown(self): self.processor_patch.stop() self.set_provider_patch.stop() self.provider_patch.stop() - self.event_logger_provider_patch.stop() - self.set_event_logger_provider_patch.stop() root_logger = getLogger("root") root_logger.handlers = [ handler @@ -634,12 +641,6 @@ def test_logging_init_empty(self): provider.resource.attributes.get("telemetry.auto.version"), "auto-version", ) - self.event_logger_provider_mock.assert_called_once_with( - logger_provider=provider - ) - self.set_event_logger_provider_mock.assert_called_once_with( - self.event_logger_provider_instance_mock - ) @patch.dict( environ, diff --git a/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py b/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py index c373658222b..ed210f27973 100644 --- a/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py +++ b/tests/opentelemetry-test-utils/src/opentelemetry/test/globals_test.py @@ -14,7 +14,6 @@ import unittest -from opentelemetry import _events as events_api from opentelemetry import trace as trace_api from opentelemetry._logs import _internal as logging_api from opentelemetry.metrics import _internal as metrics_api @@ -46,16 +45,6 @@ def reset_logging_globals() -> None: logging_api._PROXY_LOGGER_PROVIDER = logging_api.ProxyLoggerProvider() # type: ignore[attr-defined] -# pylint: disable=protected-access -def reset_event_globals() -> None: - """WARNING: only use this for tests.""" - events_api._EVENT_LOGGER_PROVIDER_SET_ONCE = Once() # type: ignore[attr-defined] - events_api._EVENT_LOGGER_PROVIDER = None # type: ignore[attr-defined] - events_api._PROXY_EVENT_LOGGER_PROVIDER = ( - events_api.ProxyEventLoggerProvider() - ) # type: ignore[attr-defined] - - class TraceGlobalsTest(unittest.TestCase): """Resets trace API globals in setUp/tearDown @@ -99,18 +88,3 @@ def setUp(self) -> None: def tearDown(self) -> None: super().tearDown() reset_logging_globals() - - -class EventsGlobalsTest(unittest.TestCase): - """Resets logging API globals in setUp/tearDown - - Use as a base class or mixin for your test that modifies logging API globals. - """ - - def setUp(self) -> None: - super().setUp() - reset_event_globals() - - def tearDown(self) -> None: - super().tearDown() - reset_event_globals()