From 30bcea7bfa8cb766eb60421165da9beb08fbb46f Mon Sep 17 00:00:00 2001 From: Tom Monk Date: Mon, 11 Mar 2024 17:10:22 -0700 Subject: [PATCH] SNOW-1063081 Bump opentelemetry-python dependencies to 1.23.0 --- anaconda/meta.yaml | 6 +- setup.py | 6 +- .../encoder/otlp/proto/common/log_encoder.py | 22 --- .../otlp/proto/common/metrics_encoder.py | 21 --- .../otlp/proto/common/trace_encoder.py | 23 --- .../exporter/otlp/proto/logs/__init__.py | 92 ++++++----- .../exporter/otlp/proto/metrics/__init__.py | 8 +- .../exporter/otlp/proto/traces/__init__.py | 8 +- tests/test_log_encoder.py | 46 ++++-- tests/test_metrics_encoder.py | 156 ++++++++++++++++-- tests/test_proto_logs_exporter.py | 4 +- tests/test_trace_encoder.py | 25 +-- 12 files changed, 255 insertions(+), 162 deletions(-) delete mode 100644 src/snowflake/telemetry/_internal/encoder/otlp/proto/common/log_encoder.py delete mode 100644 src/snowflake/telemetry/_internal/encoder/otlp/proto/common/metrics_encoder.py delete mode 100644 src/snowflake/telemetry/_internal/encoder/otlp/proto/common/trace_encoder.py diff --git a/anaconda/meta.yaml b/anaconda/meta.yaml index 695b6cd..59260af 100644 --- a/anaconda/meta.yaml +++ b/anaconda/meta.yaml @@ -11,9 +11,9 @@ requirements: - setuptools >=40.0.0 run: - python - - opentelemetry-api ==1.12.0 - - opentelemetry-sdk ==1.12.0 - - opentelemetry-exporter-otlp ==1.12.0 + - opentelemetry-api ==1.23.0 + - opentelemetry-exporter-otlp-proto-common ==1.23.0 + - opentelemetry-sdk ==1.23.0 about: home: https://www.snowflake.com/ diff --git a/setup.py b/setup.py index 02031f5..235d270 100644 --- a/setup.py +++ b/setup.py @@ -22,9 +22,9 @@ long_description=LONG_DESCRIPTION, install_requires=[ "setuptools >= 40.0.0, < 66.0.0", - "opentelemetry-api == 1.12.0", - "opentelemetry-exporter-otlp == 1.12.0", - "opentelemetry-sdk == 1.12.0", + "opentelemetry-api == 1.23.0", + "opentelemetry-exporter-otlp-proto-common == 1.23.0", + "opentelemetry-sdk == 1.23.0", ], packages=find_namespace_packages( where='src' diff --git a/src/snowflake/telemetry/_internal/encoder/otlp/proto/common/log_encoder.py b/src/snowflake/telemetry/_internal/encoder/otlp/proto/common/log_encoder.py deleted file mode 100644 index 3ae6b62..0000000 --- a/src/snowflake/telemetry/_internal/encoder/otlp/proto/common/log_encoder.py +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2012-2024 Snowflake Computing Inc. All rights reserved. -# - -""" -This module is a temporary bridge from opentelemetry 1.12.0 our current -dependency, which does not have common encoder functions to the later versions -of opentelemetry, which do have common encoder functions in the -opentelemetry-exporter-otlp-proto-common package. -""" - -from typing import Sequence - -from opentelemetry.exporter.otlp.proto.http._log_exporter import encoder -from opentelemetry.proto.collector.logs.v1.logs_service_pb2 import ExportLogsServiceRequest -from opentelemetry.sdk._logs import LogData - - -def _encode_logs(batch: Sequence[LogData]) -> ExportLogsServiceRequest: - # Will no longer rely on _encode_resource_logs after we upgrade to v1.19.0 or later - resource_logs = encoder._encode_resource_logs(batch) # pylint: disable=protected-access - return ExportLogsServiceRequest(resource_logs=resource_logs) diff --git a/src/snowflake/telemetry/_internal/encoder/otlp/proto/common/metrics_encoder.py b/src/snowflake/telemetry/_internal/encoder/otlp/proto/common/metrics_encoder.py deleted file mode 100644 index 3cf313d..0000000 --- a/src/snowflake/telemetry/_internal/encoder/otlp/proto/common/metrics_encoder.py +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright (c) 2012-2024 Snowflake Computing Inc. All rights reserved. -# - -""" -This module is a temporary bridge from opentelemetry 1.12.0 our current -dependency, which does not have common encoder functions to the later versions -of opentelemetry, which do have common encoder functions in the -opentelemetry-exporter-otlp-proto-common package. -""" - -from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter -from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import ExportMetricsServiceRequest -from opentelemetry.sdk.metrics.export import MetricsData - - -_exporter = OTLPMetricExporter() - -def _encode_metrics(data: MetricsData) -> ExportMetricsServiceRequest: - # Will no longer rely on _translate_data after we upgrade to v1.19.0 or later - return _exporter._translate_data(data) # pylint: disable=protected-access diff --git a/src/snowflake/telemetry/_internal/encoder/otlp/proto/common/trace_encoder.py b/src/snowflake/telemetry/_internal/encoder/otlp/proto/common/trace_encoder.py deleted file mode 100644 index 19ec276..0000000 --- a/src/snowflake/telemetry/_internal/encoder/otlp/proto/common/trace_encoder.py +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2012-2024 Snowflake Computing Inc. All rights reserved. -# - -""" -This module is a temporary bridge from opentelemetry 1.12.0 our current -dependency, which does not have common encoder functions to the later versions -of opentelemetry, which do have common encoder functions in the -opentelemetry-exporter-otlp-proto-common package. -""" - -from typing import Sequence - -from opentelemetry.exporter.otlp.proto.http.trace_exporter.encoder import _ProtobufEncoder -from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import ExportTraceServiceRequest -from opentelemetry.sdk.trace import ReadableSpan - - -def _encode_spans( - sdk_spans: Sequence[ReadableSpan], -) -> ExportTraceServiceRequest: - # Will no longer rely on _ProtobufEncoder after we upgrade to v1.19.0 or later - return _ProtobufEncoder.encode(sdk_spans) diff --git a/src/snowflake/telemetry/_internal/exporter/otlp/proto/logs/__init__.py b/src/snowflake/telemetry/_internal/exporter/otlp/proto/logs/__init__.py index fca520a..cdb6d2e 100644 --- a/src/snowflake/telemetry/_internal/exporter/otlp/proto/logs/__init__.py +++ b/src/snowflake/telemetry/_internal/exporter/otlp/proto/logs/__init__.py @@ -19,15 +19,16 @@ import threading import typing import opentelemetry.sdk.util.instrumentation as otel_instrumentation +import opentelemetry.sdk._logs._internal as _logs_internal +from opentelemetry.exporter.otlp.proto.common._log_encoder import ( + encode_logs, +) from opentelemetry.proto.logs.v1.logs_pb2 import LogsData from opentelemetry.sdk import resources from opentelemetry.sdk._logs import export from opentelemetry.sdk import _logs from opentelemetry.util import types -from snowflake.telemetry._internal.encoder.otlp.proto.common.log_encoder import ( - _encode_logs, -) # pylint: disable=too-few-public-methods @@ -69,7 +70,7 @@ def _serialize_logs_data(batch: typing.Sequence[_logs.LogData]) -> bytes: # pylint gets confused by protobuf-generated code, that's why we must # disable the no-member check below. return LogsData( - resource_logs=_encode_logs(batch).resource_logs # pylint: disable=no-member + resource_logs=encode_logs(batch).resource_logs # pylint: disable=no-member ).SerializeToString() def shutdown(self): @@ -82,19 +83,18 @@ class SnowflakeLoggingHandler(_logs.LoggingHandler): discarded by the original implementation. """ - _FILEPATH_ATTRIBUTE = "code.filepath" - _FUNCTION_NAME_ATTRIBUTE = "code.function" LOGGER_NAME_TEMP_ATTRIBUTE = "__snow.logging.temp.logger_name" def __init__( self, log_writer: LogWriter, ): - provider = _SnowflakeTelemetryLogEmitterProvider() - _logs.set_log_emitter_provider(provider) exporter = _ProtoLogExporter(log_writer) - provider.add_log_processor(export.SimpleLogProcessor(exporter)) - super().__init__() + provider = _SnowflakeTelemetryLoggerProvider() + provider.add_log_record_processor( + export.SimpleLogRecordProcessor(exporter) + ) + super().__init__(logger_provider=provider) @staticmethod def _get_snowflake_log_level_name(py_level_name): @@ -114,17 +114,11 @@ def _get_snowflake_log_level_name(py_level_name): def _get_attributes(record: logging.LogRecord) -> types.Attributes: attributes = _logs.LoggingHandler._get_attributes(record) # pylint: disable=protected-access - # Adding attributes that were discarded by the base class's - # _get_attributes() method - # TODO (SNOW-1210317) Remove these when upgrading to opentelemetry-python 1.23 - attributes[SnowflakeLoggingHandler._FILEPATH_ATTRIBUTE] = record.pathname - attributes[SnowflakeLoggingHandler._FUNCTION_NAME_ATTRIBUTE] = record.funcName - # Temporarily storing logger's name in record's attributes. - # This attribute will be removed by the emitter. + # This attribute will be removed by the logger. # - # TODO(SNOW-1210317): Upgrade to OpenTelemetry 1.20.0 or later - # and use OpenTelemetry's LoggerProvider. + # TODO (SNOW-1235374): opentelemetry-python issue #2485: Record logger + # name as the instrumentation scope name attributes[SnowflakeLoggingHandler.LOGGER_NAME_TEMP_ATTRIBUTE] = record.name return attributes @@ -136,21 +130,22 @@ def _translate(self, record: logging.LogRecord) -> _logs.LogRecord: return otel_record -class _SnowflakeTelemetryLogEmitter(_logs.LogEmitter): +class _SnowflakeTelemetryLogger(_logs.Logger): """ - A log emitter which creates an InstrumentationScope for each logger name it - encounters. + An Open Telemetry Logger which creates an InstrumentationScope for each + logger name it encounters. """ def __init__( - self, - resource: resources.Resource, - multi_log_processor: typing.Union[ - _logs.SynchronousMultiLogProcessor, _logs.ConcurrentMultiLogProcessor - ], - instrumentation_scope: otel_instrumentation.InstrumentationScope, + self, + resource: resources.Resource, + multi_log_record_processor: typing.Union[ + _logs_internal.SynchronousMultiLogRecordProcessor, + _logs_internal.ConcurrentMultiLogRecordProcessor, + ], + instrumentation_scope: otel_instrumentation.InstrumentationScope, ): - super().__init__(resource, multi_log_processor, instrumentation_scope) + super().__init__(resource, multi_log_record_processor, instrumentation_scope) self._lock = threading.Lock() self.cached_scopes = {} @@ -175,28 +170,41 @@ def emit(self, record: _logs.LogRecord): # Emitting a record with a scope that corresponds to the logger # that logged it. NOT calling the superclass here for two reasons: - # 1. LogEmitter.emit takes a LogRecord, not LogData. + # 1. Logger.emit takes a LogRecord, not LogData. # 2. It would emit a log record with the default instrumentation scope, # not with the scope we want. log_data = _logs.LogData(record, current_scope) - self._multi_log_processor.emit(log_data) + self._multi_log_record_processor.emit(log_data) -class _SnowflakeTelemetryLogEmitterProvider(_logs.LogEmitterProvider): +class _SnowflakeTelemetryLoggerProvider(_logs.LoggerProvider): """ - A log emitter provider that creates SnowflakeTelemetryLogEmitters + A LoggerProvider that creates SnowflakeTelemetryLoggers """ - - def get_log_emitter( - self, - instrumenting_module_name: str, - instrumenting_module_version: str = "", - ) -> _logs.LogEmitter: - return _SnowflakeTelemetryLogEmitter( + def __init__( + self, + resource: resources.Resource = None, + shutdown_on_exit: bool = True, + multi_log_record_processor: typing.Union[ + _logs_internal.SynchronousMultiLogRecordProcessor, + _logs_internal.ConcurrentMultiLogRecordProcessor, + ] = None, + ): + super().__init__(resource, shutdown_on_exit, multi_log_record_processor) + + def get_logger( + self, + name: str, + version: types.Optional[str] = None, + schema_url: types.Optional[str] = None, + ) -> _logs.Logger: + return _SnowflakeTelemetryLogger( self._resource, - self._multi_log_processor, + self._multi_log_record_processor, otel_instrumentation.InstrumentationScope( - instrumenting_module_name, instrumenting_module_version + name, + version, + schema_url, ), ) diff --git a/src/snowflake/telemetry/_internal/exporter/otlp/proto/metrics/__init__.py b/src/snowflake/telemetry/_internal/exporter/otlp/proto/metrics/__init__.py index c1540f2..4af1c78 100644 --- a/src/snowflake/telemetry/_internal/exporter/otlp/proto/metrics/__init__.py +++ b/src/snowflake/telemetry/_internal/exporter/otlp/proto/metrics/__init__.py @@ -17,6 +17,9 @@ from typing import Dict import opentelemetry +from opentelemetry.exporter.otlp.proto.common.metrics_encoder import ( + encode_metrics, +) from opentelemetry.proto.metrics.v1.metrics_pb2 import MetricsData as PB2MetricsData from opentelemetry.sdk.metrics.export import ( AggregationTemporality, @@ -24,9 +27,6 @@ MetricExporter, MetricsData, ) -from snowflake.telemetry._internal.encoder.otlp.proto.common.metrics_encoder import ( - _encode_metrics, -) # pylint: disable=too-few-public-methods @@ -82,7 +82,7 @@ def _serialize_metrics_data(data: MetricsData) -> bytes: # pylint gets confused by protobuf-generated code, that's why we must # disable the no-member check below. return PB2MetricsData( - resource_metrics=_encode_metrics(data).resource_metrics # pylint: disable=no-member + resource_metrics=encode_metrics(data).resource_metrics # pylint: disable=no-member ).SerializeToString() def force_flush(self, timeout_millis: float = 10_000) -> bool: diff --git a/src/snowflake/telemetry/_internal/exporter/otlp/proto/traces/__init__.py b/src/snowflake/telemetry/_internal/exporter/otlp/proto/traces/__init__.py index dab2082..1187f0b 100644 --- a/src/snowflake/telemetry/_internal/exporter/otlp/proto/traces/__init__.py +++ b/src/snowflake/telemetry/_internal/exporter/otlp/proto/traces/__init__.py @@ -16,15 +16,15 @@ import abc import typing +from opentelemetry.exporter.otlp.proto.common.trace_encoder import ( + encode_spans, +) from opentelemetry.proto.trace.v1.trace_pb2 import TracesData from opentelemetry.sdk.trace import ReadableSpan from opentelemetry.sdk.trace.export import ( SpanExportResult, SpanExporter, ) -from snowflake.telemetry._internal.encoder.otlp.proto.common.trace_encoder import ( - _encode_spans, -) # pylint: disable=too-few-public-methods @@ -72,7 +72,7 @@ def _serialize_traces_data( # pylint gets confused by protobuf-generated code, that's why we must # disable the no-member check below. return TracesData( - resource_spans=_encode_spans(sdk_spans).resource_spans # pylint: disable=no-member + resource_spans=encode_spans(sdk_spans).resource_spans # pylint: disable=no-member ).SerializeToString() def shutdown(self) -> None: diff --git a/tests/test_log_encoder.py b/tests/test_log_encoder.py index bc22591..28bf147 100644 --- a/tests/test_log_encoder.py +++ b/tests/test_log_encoder.py @@ -13,22 +13,16 @@ # limitations under the License. import unittest -import pytest from typing import List, Tuple -from opentelemetry.sdk._logs import SeverityNumber -from opentelemetry.exporter.otlp.proto.http.trace_exporter.encoder import ( +from opentelemetry._logs import SeverityNumber +from opentelemetry.exporter.otlp.proto.common._internal import ( _encode_attributes, _encode_span_id, _encode_trace_id, _encode_value, ) -from snowflake.telemetry._internal.encoder.otlp.proto.common.log_encoder import ( - _encode_logs, -) -from snowflake.telemetry._internal.exporter.otlp.proto.logs import ( - _ProtoLogExporter, -) +from opentelemetry.exporter.otlp.proto.common._log_encoder import encode_logs from opentelemetry.proto.collector.logs.v1.logs_service_pb2 import ( ExportLogsServiceRequest, ) @@ -46,17 +40,20 @@ from opentelemetry.proto.resource.v1.resource_pb2 import ( Resource as PB2Resource, ) -from opentelemetry.sdk._logs import LogData +from opentelemetry.sdk._logs import LogData, LogLimits from opentelemetry.sdk._logs import LogRecord as SDKLogRecord from opentelemetry.sdk.resources import Resource as SDKResource from opentelemetry.sdk.util.instrumentation import InstrumentationScope from opentelemetry.trace import TraceFlags +from snowflake.telemetry._internal.exporter.otlp.proto.logs import ( + _ProtoLogExporter, +) class TestOTLPLogEncoder(unittest.TestCase): def test_encode(self): sdk_logs, expected_encoding = self.get_test_logs() - self.assertEqual(_encode_logs(sdk_logs), expected_encoding) + self.assertEqual(encode_logs(sdk_logs), expected_encoding) def test_serialize_logs_data(self): sdk_logs, expected_encoding = self.get_test_logs() @@ -64,6 +61,19 @@ def test_serialize_logs_data(self): self.assertEqual(_ProtoLogExporter._serialize_logs_data(sdk_logs), PB2LogsData(resource_logs=expected_encoding.resource_logs).SerializeToString()) + 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.assertEqual( + # pylint:disable=no-member + encoded_logs.resource_logs[0] + .scope_logs[0] + .log_records[0] + .dropped_attributes_count, + 2, + ) + @staticmethod def _get_sdk_log_data() -> List[LogData]: log1 = LogData( @@ -75,7 +85,10 @@ def _get_sdk_log_data() -> List[LogData]: 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=SDKResource( + {"first_resource": "value"}, + "resource_schema_url", + ), attributes={"a": 1, "b": "c"}, ), instrumentation_scope=InstrumentationScope( @@ -124,7 +137,10 @@ def _get_sdk_log_data() -> List[LogData]: severity_text="INFO", severity_number=SeverityNumber.INFO, body="Love is the one thing that transcends time and space", - resource=SDKResource({"first_resource": "value"}), + resource=SDKResource( + {"first_resource": "value"}, + "resource_schema_url", + ), attributes={"filename": "model.py", "func_name": "run_method"}, ), instrumentation_scope=InstrumentationScope( @@ -206,6 +222,7 @@ def get_test_logs( ], ), ], + schema_url="resource_schema_url", ), PB2ResourceLogs( resource=PB2Resource( @@ -277,7 +294,8 @@ def _get_test_logs_dropped_attributes() -> List[LogData]: 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"} + attributes={"a": 1, "b": "c", "user_id": "B121092"}, + limits=LogLimits(max_attributes=1), ), instrumentation_scope=InstrumentationScope( "first_name", "first_version" diff --git a/tests/test_metrics_encoder.py b/tests/test_metrics_encoder.py index 05b7a3b..2f0698c 100644 --- a/tests/test_metrics_encoder.py +++ b/tests/test_metrics_encoder.py @@ -15,11 +15,8 @@ # pylint: disable=protected-access import unittest -from snowflake.telemetry._internal.encoder.otlp.proto.common.metrics_encoder import ( - _encode_metrics, -) -from snowflake.telemetry._internal.exporter.otlp.proto.metrics import ( - ProtoMetricExporter, +from opentelemetry.exporter.otlp.proto.common.metrics_encoder import ( + encode_metrics, ) from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import ( ExportMetricsServiceRequest, @@ -33,7 +30,11 @@ from opentelemetry.proto.resource.v1.resource_pb2 import ( Resource as OTLPResource, ) -from opentelemetry.sdk.metrics.export import AggregationTemporality +from opentelemetry.sdk.metrics.export import AggregationTemporality, Buckets +from opentelemetry.sdk.metrics.export import ( + ExponentialHistogram as ExponentialHistogramType, +) +from opentelemetry.sdk.metrics.export import ExponentialHistogramDataPoint from opentelemetry.sdk.metrics.export import Histogram as HistogramType from opentelemetry.sdk.metrics.export import ( HistogramDataPoint, @@ -46,6 +47,9 @@ from opentelemetry.sdk.util.instrumentation import ( InstrumentationScope as SDKInstrumentationScope, ) +from snowflake.telemetry._internal.exporter.otlp.proto.metrics import ( + ProtoMetricExporter, +) from snowflake.telemetry.test.metrictestutil import _generate_gauge, _generate_sum @@ -98,6 +102,7 @@ def test_encode_sum_int(self): expected = ExportMetricsServiceRequest( resource_metrics=[ pb2.ResourceMetrics( + schema_url="resource_schema_url", resource=OTLPResource( attributes=[ KeyValue(key="a", value=AnyValue(int_value=1)), @@ -148,7 +153,7 @@ def test_encode_sum_int(self): ) ] ) - actual = _encode_metrics(metrics_data) + actual = encode_metrics(metrics_data) self.assertEqual(expected, actual) self.assertEqual(pb2.MetricsData(resource_metrics=actual.resource_metrics).SerializeToString(), ProtoMetricExporter._serialize_metrics_data(metrics_data)) @@ -179,6 +184,7 @@ def test_encode_sum_double(self): expected = ExportMetricsServiceRequest( resource_metrics=[ pb2.ResourceMetrics( + schema_url="resource_schema_url", resource=OTLPResource( attributes=[ KeyValue(key="a", value=AnyValue(int_value=1)), @@ -229,7 +235,7 @@ def test_encode_sum_double(self): ) ] ) - actual = _encode_metrics(metrics_data) + actual = encode_metrics(metrics_data) self.assertEqual(expected, actual) self.assertEqual(pb2.MetricsData(resource_metrics=actual.resource_metrics).SerializeToString(), ProtoMetricExporter._serialize_metrics_data(metrics_data)) @@ -260,6 +266,7 @@ def test_encode_gauge_int(self): expected = ExportMetricsServiceRequest( resource_metrics=[ pb2.ResourceMetrics( + schema_url="resource_schema_url", resource=OTLPResource( attributes=[ KeyValue(key="a", value=AnyValue(int_value=1)), @@ -307,7 +314,7 @@ def test_encode_gauge_int(self): ) ] ) - actual = _encode_metrics(metrics_data) + actual = encode_metrics(metrics_data) self.assertEqual(expected, actual) self.assertEqual(pb2.MetricsData(resource_metrics=actual.resource_metrics).SerializeToString(), ProtoMetricExporter._serialize_metrics_data(metrics_data)) @@ -338,6 +345,7 @@ def test_encode_gauge_double(self): expected = ExportMetricsServiceRequest( resource_metrics=[ pb2.ResourceMetrics( + schema_url="resource_schema_url", resource=OTLPResource( attributes=[ KeyValue(key="a", value=AnyValue(int_value=1)), @@ -385,7 +393,7 @@ def test_encode_gauge_double(self): ) ] ) - actual = _encode_metrics(metrics_data) + actual = encode_metrics(metrics_data) self.assertEqual(expected, actual) self.assertEqual(pb2.MetricsData(resource_metrics=actual.resource_metrics).SerializeToString(), ProtoMetricExporter._serialize_metrics_data(metrics_data)) @@ -416,6 +424,7 @@ def test_encode_histogram(self): expected = ExportMetricsServiceRequest( resource_metrics=[ pb2.ResourceMetrics( + schema_url="resource_schema_url", resource=OTLPResource( attributes=[ KeyValue(key="a", value=AnyValue(int_value=1)), @@ -471,7 +480,7 @@ def test_encode_histogram(self): ) ] ) - actual = _encode_metrics(metrics_data) + actual = encode_metrics(metrics_data) self.assertEqual(expected, actual) self.assertEqual(pb2.MetricsData(resource_metrics=actual.resource_metrics).SerializeToString(), ProtoMetricExporter._serialize_metrics_data(metrics_data)) @@ -520,6 +529,7 @@ def test_encode_multiple_scope_histogram(self): expected = ExportMetricsServiceRequest( resource_metrics=[ pb2.ResourceMetrics( + schema_url="resource_schema_url", resource=OTLPResource( attributes=[ KeyValue(key="a", value=AnyValue(int_value=1)), @@ -694,7 +704,129 @@ def test_encode_multiple_scope_histogram(self): ) ] ) - actual = _encode_metrics(metrics_data) + actual = encode_metrics(metrics_data) + self.assertEqual(expected, actual) + self.assertEqual(pb2.MetricsData(resource_metrics=actual.resource_metrics).SerializeToString(), + ProtoMetricExporter._serialize_metrics_data(metrics_data)) + + def test_encode_exponential_histogram(self): + exponential_histogram = Metric( + name="exponential_histogram", + description="description", + unit="unit", + data=ExponentialHistogramType( + data_points=[ + ExponentialHistogramDataPoint( + attributes={"a": 1, "b": True}, + start_time_unix_nano=0, + time_unix_nano=1, + count=2, + sum=3, + scale=4, + zero_count=5, + positive=Buckets(offset=6, bucket_counts=[7, 8]), + negative=Buckets(offset=9, bucket_counts=[10, 11]), + flags=12, + min=13.0, + max=14.0, + ) + ], + aggregation_temporality=AggregationTemporality.DELTA, + ), + ) + + metrics_data = MetricsData( + resource_metrics=[ + ResourceMetrics( + resource=Resource( + attributes={"a": 1, "b": False}, + schema_url="resource_schema_url", + ), + scope_metrics=[ + ScopeMetrics( + scope=SDKInstrumentationScope( + name="first_name", + version="first_version", + schema_url="insrumentation_scope_schema_url", + ), + metrics=[exponential_histogram], + schema_url="instrumentation_scope_schema_url", + ) + ], + schema_url="resource_schema_url", + ) + ] + ) + expected = ExportMetricsServiceRequest( + resource_metrics=[ + pb2.ResourceMetrics( + schema_url="resource_schema_url", + resource=OTLPResource( + attributes=[ + KeyValue(key="a", value=AnyValue(int_value=1)), + KeyValue( + key="b", value=AnyValue(bool_value=False) + ), + ] + ), + scope_metrics=[ + pb2.ScopeMetrics( + scope=InstrumentationScope( + name="first_name", version="first_version" + ), + metrics=[ + pb2.Metric( + name="exponential_histogram", + unit="unit", + description="description", + exponential_histogram=pb2.ExponentialHistogram( + data_points=[ + pb2.ExponentialHistogramDataPoint( + attributes=[ + KeyValue( + key="a", + value=AnyValue( + int_value=1 + ), + ), + KeyValue( + key="b", + value=AnyValue( + bool_value=True + ), + ), + ], + start_time_unix_nano=0, + time_unix_nano=1, + count=2, + sum=3, + scale=4, + zero_count=5, + positive=pb2.ExponentialHistogramDataPoint.Buckets( + offset=6, + bucket_counts=[7, 8], + ), + negative=pb2.ExponentialHistogramDataPoint.Buckets( + offset=9, + bucket_counts=[10, 11], + ), + flags=12, + exemplars=[], + min=13.0, + max=14.0, + ) + ], + aggregation_temporality=AggregationTemporality.DELTA, + ), + ) + ], + ) + ], + ) + ] + ) + # pylint: disable=protected-access + actual = encode_metrics(metrics_data) self.assertEqual(expected, actual) self.assertEqual(pb2.MetricsData(resource_metrics=actual.resource_metrics).SerializeToString(), ProtoMetricExporter._serialize_metrics_data(metrics_data)) diff --git a/tests/test_proto_logs_exporter.py b/tests/test_proto_logs_exporter.py index 39e92d0..7cb8078 100644 --- a/tests/test_proto_logs_exporter.py +++ b/tests/test_proto_logs_exporter.py @@ -123,7 +123,7 @@ def test_snowflake_logging_handler_scoped_logger(self): this_method_name = inspect.currentframe().f_code.co_name self.log_writer.clear() self.root_logger.critical("critical, something is wrong at root scope") - local_logger = logging.getLogger("test_proto_logs_exporter") + local_logger = logging.getLogger("tests") local_logger.critical("critical, something is wrong at local scope") finished_protos = self.log_writer.get_finished_protos() self.assertEqual(len(finished_protos), 2) @@ -137,7 +137,7 @@ def test_snowflake_logging_handler_scoped_logger(self): this_method_name ) local_log_record = finished_protos[1].resource_logs[0].scope_logs[0].log_records[0] - self.assertEqual(finished_protos[1].resource_logs[0].scope_logs[0].scope.name, "test_proto_logs_exporter") + self.assertEqual(finished_protos[1].resource_logs[0].scope_logs[0].scope.name, "tests") self._log_record_check_helper( local_log_record, "critical, something is wrong at local scope", diff --git a/tests/test_trace_encoder.py b/tests/test_trace_encoder.py index 289c419..9983c01 100644 --- a/tests/test_trace_encoder.py +++ b/tests/test_trace_encoder.py @@ -17,18 +17,15 @@ import unittest from typing import List, Tuple -from opentelemetry.exporter.otlp.proto.http.trace_exporter.encoder import ( - _SPAN_KIND_MAP, +from opentelemetry.exporter.otlp.proto.common._internal import ( _encode_span_id, - _encode_status, _encode_trace_id, ) -from snowflake.telemetry._internal.encoder.otlp.proto.common.trace_encoder import ( - _encode_spans, -) -from snowflake.telemetry._internal.exporter.otlp.proto.traces import ( - ProtoSpanExporter, +from opentelemetry.exporter.otlp.proto.common._internal.trace_encoder import ( + _SPAN_KIND_MAP, + _encode_status, ) +from opentelemetry.exporter.otlp.proto.common.trace_encoder import encode_spans from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import ( ExportTraceServiceRequest as PB2ExportTraceServiceRequest, ) @@ -42,7 +39,7 @@ ) from opentelemetry.proto.trace.v1.trace_pb2 import ( ResourceSpans as PB2ResourceSpans, - TracesData as PB2TracesData + TracesData as PB2TracesData, ) from opentelemetry.proto.trace.v1.trace_pb2 import ScopeSpans as PB2ScopeSpans from opentelemetry.proto.trace.v1.trace_pb2 import Span as PB2SPan @@ -59,12 +56,15 @@ from opentelemetry.trace import TraceFlags as SDKTraceFlags from opentelemetry.trace.status import Status as SDKStatus from opentelemetry.trace.status import StatusCode as SDKStatusCode +from snowflake.telemetry._internal.exporter.otlp.proto.traces import ( + ProtoSpanExporter, +) class TestOTLPTraceEncoder(unittest.TestCase): def test_encode_spans(self): otel_spans, expected_encoding = self.get_exhaustive_test_spans() - self.assertEqual(_encode_spans(otel_spans), expected_encoding) + self.assertEqual(encode_spans(otel_spans), expected_encoding) def test_serialize_traces_data(self): otel_spans, expected_encoding = self.get_exhaustive_test_spans() @@ -120,7 +120,7 @@ def get_exhaustive_otel_span_list() -> List[SDKSpan]: links=( SDKLink(context=other_context, attributes={"key_bool": True}), ), - resource=SDKResource({}), + resource=SDKResource({}, "resource_schema_url"), ) span1.start(start_time=start_times[0]) span1.set_attribute("key_bool", False) @@ -152,7 +152,7 @@ def get_exhaustive_otel_span_list() -> List[SDKSpan]: name="test-span-4", context=other_context, parent=None, - resource=SDKResource({}), + resource=SDKResource({}, "resource_schema_url"), instrumentation_scope=SDKInstrumentationScope( name="name", version="version" ), @@ -172,6 +172,7 @@ def get_exhaustive_test_spans( pb2_service_request = PB2ExportTraceServiceRequest( resource_spans=[ PB2ResourceSpans( + schema_url="resource_schema_url", resource=PB2Resource(), scope_spans=[ PB2ScopeSpans(