Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#4958](https://github.com/open-telemetry/opentelemetry-python/pull/4958))
- `opentelemetry-sdk`: fix type annotations on `MetricReader` and related types
([#4938](https://github.com/open-telemetry/opentelemetry-python/pull/4938/))
- Implement log creation metric
([#4935](https://github.com/open-telemetry/opentelemetry-python/pull/4935))
- `opentelemetry-sdk`: upgrade vendored OTel configuration schema from v1.0.0-rc.3 to v1.0.0
([#4965](https://github.com/open-telemetry/opentelemetry-python/pull/4965))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
from opentelemetry.attributes import _VALID_ANY_VALUE_TYPES, BoundedAttributes
from opentelemetry.context import get_current
from opentelemetry.context.context import Context
from opentelemetry.metrics import MeterProvider, get_meter_provider
from opentelemetry.sdk._logs._internal._logger_metrics import LoggerMetrics
from opentelemetry.sdk.environment_variables import (
OTEL_ATTRIBUTE_COUNT_LIMIT,
OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT,
Expand Down Expand Up @@ -638,6 +640,8 @@ def __init__(
ConcurrentMultiLogRecordProcessor,
],
instrumentation_scope: InstrumentationScope,
*,
logger_metrics: LoggerMetrics,
):
super().__init__(
instrumentation_scope.name,
Expand All @@ -648,6 +652,7 @@ def __init__(
self._resource = resource
self._multi_log_record_processor = multi_log_record_processor
self._instrumentation_scope = instrumentation_scope
self._logger_metrics = logger_metrics

@property
def resource(self):
Expand Down Expand Up @@ -700,6 +705,7 @@ def emit(
instrumentation_scope=self._instrumentation_scope,
)

self._logger_metrics.emit_log()
Comment thread
xrmx marked this conversation as resolved.
self._multi_log_record_processor.on_emit(writable_record)


Expand All @@ -711,6 +717,8 @@ def __init__(
multi_log_record_processor: SynchronousMultiLogRecordProcessor
| ConcurrentMultiLogRecordProcessor
| None = None,
*,
meter_provider: MeterProvider | None = None,
):
if resource is None:
self._resource = Resource.create({})
Expand All @@ -719,6 +727,9 @@ def __init__(
self._multi_log_record_processor = (
multi_log_record_processor or SynchronousMultiLogRecordProcessor()
)
self._logger_metrics = LoggerMetrics(
meter_provider or get_meter_provider()
)
disabled = environ.get(OTEL_SDK_DISABLED, "")
self._disabled = disabled.lower().strip() == "true"
self._at_exit_handler = None
Expand Down Expand Up @@ -747,6 +758,7 @@ def _get_logger_no_cache(
schema_url,
attributes,
),
logger_metrics=self._logger_metrics,
)

def _get_logger_cached(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# 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 opentelemetry import metrics as metrics_api
from opentelemetry.semconv._incubating.metrics.otel_metrics import (
create_otel_sdk_log_created,
)


class LoggerMetrics:
Comment thread
xrmx marked this conversation as resolved.
def __init__(self, meter_provider: metrics_api.MeterProvider) -> None:
meter = meter_provider.get_meter("opentelemetry-sdk")
self._created_logs = create_otel_sdk_log_created(meter)
Comment thread
xrmx marked this conversation as resolved.

def emit_log(self) -> None:
self._created_logs.add(1)
3 changes: 1 addition & 2 deletions opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
)
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import sampling
from opentelemetry.sdk.trace._tracer_metrics import TracerMetrics
from opentelemetry.sdk.trace.id_generator import IdGenerator, RandomIdGenerator
from opentelemetry.sdk.util import BoundedList
from opentelemetry.sdk.util.instrumentation import (
Expand All @@ -81,8 +82,6 @@
from opentelemetry.util import types
from opentelemetry.util._decorator import _agnosticcontextmanager

from ._tracer_metrics import TracerMetrics

logger = logging.getLogger(__name__)

_DEFAULT_OTEL_ATTRIBUTE_COUNT_LIMIT = 128
Expand Down
3 changes: 3 additions & 0 deletions opentelemetry-sdk/tests/logs/test_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@

from opentelemetry._logs import LogRecord, SeverityNumber
from opentelemetry.context import get_current
from opentelemetry.metrics import NoOpMeterProvider
from opentelemetry.sdk._logs import (
Logger,
LoggerProvider,
ReadableLogRecord,
)
from opentelemetry.sdk._logs._internal import (
LoggerMetrics,
NoOpLogger,
SynchronousMultiLogRecordProcessor,
)
Expand Down Expand Up @@ -148,6 +150,7 @@ def _get_logger():
"schema_url",
{"an": "attribute"},
),
logger_metrics=LoggerMetrics(NoOpMeterProvider()),
)
return logger, log_record_processor_mock

Expand Down
59 changes: 59 additions & 0 deletions opentelemetry-sdk/tests/logs/test_sdk_metrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# 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 unittest import TestCase

from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import InMemoryMetricReader


class TestLoggerProviderMetrics(TestCase):
def setUp(self):
self.metric_reader = InMemoryMetricReader()
self.meter_provider = MeterProvider(
metric_readers=[self.metric_reader]
)

def tearDown(self):
self.meter_provider.shutdown()

def assert_created_logs(self, metric_data, value, attrs):
metrics = metric_data.resource_metrics[0].scope_metrics[0].metrics
created_logs_metric = next(
(m for m in metrics if m.name == "otel.sdk.log.created"), None
)
self.assertIsNotNone(created_logs_metric)
self.assertEqual(created_logs_metric.data.data_points[0].value, value)
self.assertDictEqual(
created_logs_metric.data.data_points[0].attributes, attrs
)

def test_create_logs(self):
logger_provider = LoggerProvider(meter_provider=self.meter_provider)
logger = logger_provider.get_logger("test")
logger.emit(body="log1")
metric_data = self.metric_reader.get_metrics_data()
self.assert_created_logs(
metric_data,
1,
{},
)
logger.emit(body="log2")
metric_data = self.metric_reader.get_metrics_data()
self.assert_created_logs(
metric_data,
2,
{},
)
Loading