增加环绕侦察场景适配
This commit is contained in:
@@ -22,13 +22,13 @@ from __future__ import annotations
|
||||
import logging
|
||||
import logging.config
|
||||
import os
|
||||
import warnings
|
||||
from abc import ABC, abstractmethod
|
||||
from os import environ
|
||||
from typing import Any, Callable, Mapping, Sequence, Type, Union
|
||||
|
||||
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,
|
||||
@@ -37,9 +37,11 @@ from opentelemetry.environment_variables import (
|
||||
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._logs.export import (
|
||||
BatchLogRecordProcessor,
|
||||
LogRecordExporter,
|
||||
)
|
||||
from opentelemetry.sdk.environment_variables import (
|
||||
_OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED,
|
||||
OTEL_EXPORTER_OTLP_LOGS_PROTOCOL,
|
||||
@@ -97,7 +99,7 @@ ExporterArgsMap = Mapping[
|
||||
Type[SpanExporter],
|
||||
Type[MetricExporter],
|
||||
Type[MetricReader],
|
||||
Type[LogExporter],
|
||||
Type[LogRecordExporter],
|
||||
],
|
||||
Mapping[str, Any],
|
||||
]
|
||||
@@ -250,7 +252,7 @@ def _init_metrics(
|
||||
|
||||
|
||||
def _init_logging(
|
||||
exporters: dict[str, Type[LogExporter]],
|
||||
exporters: dict[str, Type[LogRecordExporter]],
|
||||
resource: Resource | None = None,
|
||||
setup_logging_handler: bool = True,
|
||||
exporter_args_map: ExporterArgsMap | None = None,
|
||||
@@ -265,8 +267,19 @@ def _init_logging(
|
||||
BatchLogRecordProcessor(exporter_class(**exporter_args))
|
||||
)
|
||||
|
||||
event_logger_provider = EventLoggerProvider(logger_provider=provider)
|
||||
set_event_logger_provider(event_logger_provider)
|
||||
# silence warnings from internal users until we drop the deprecated Events API
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", category=DeprecationWarning)
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from opentelemetry._events import ( # noqa: PLC0415
|
||||
set_event_logger_provider,
|
||||
)
|
||||
from opentelemetry.sdk._events import ( # noqa: PLC0415
|
||||
EventLoggerProvider,
|
||||
)
|
||||
|
||||
event_logger_provider = EventLoggerProvider(logger_provider=provider)
|
||||
set_event_logger_provider(event_logger_provider)
|
||||
|
||||
if setup_logging_handler:
|
||||
# Add OTel handler
|
||||
@@ -309,7 +322,7 @@ def _import_exporters(
|
||||
) -> tuple[
|
||||
dict[str, Type[SpanExporter]],
|
||||
dict[str, Union[Type[MetricExporter], Type[MetricReader]]],
|
||||
dict[str, Type[LogExporter]],
|
||||
dict[str, Type[LogRecordExporter]],
|
||||
]:
|
||||
trace_exporters = {}
|
||||
metric_exporters = {}
|
||||
@@ -345,7 +358,7 @@ def _import_exporters(
|
||||
) in _import_config_components(
|
||||
log_exporter_names, "opentelemetry_logs_exporter"
|
||||
):
|
||||
if issubclass(exporter_impl, LogExporter):
|
||||
if issubclass(exporter_impl, LogRecordExporter):
|
||||
log_exporters[exporter_name] = exporter_impl
|
||||
else:
|
||||
raise RuntimeError(f"{exporter_name} is not a log exporter")
|
||||
|
||||
@@ -13,26 +13,31 @@
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
import warnings
|
||||
from time import time_ns
|
||||
from typing import Optional
|
||||
|
||||
from typing_extensions import deprecated
|
||||
|
||||
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 (
|
||||
LogDeprecatedInitWarning,
|
||||
Logger,
|
||||
LoggerProvider,
|
||||
from opentelemetry._logs import (
|
||||
LogRecord,
|
||||
NoOpLogger,
|
||||
SeverityNumber,
|
||||
get_logger_provider,
|
||||
)
|
||||
from opentelemetry.sdk._logs import Logger, LoggerProvider
|
||||
from opentelemetry.util.types import _ExtendedAttributes
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@deprecated(
|
||||
"You should use `Logger` instead. "
|
||||
"Deprecated since version 1.39.0 and will be removed in a future release."
|
||||
)
|
||||
class EventLogger(APIEventLogger):
|
||||
def __init__(
|
||||
self,
|
||||
@@ -58,25 +63,24 @@ class EventLogger(APIEventLogger):
|
||||
return
|
||||
span_context = trace.get_current_span().get_span_context()
|
||||
|
||||
# silence deprecation warnings from internal users
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", category=LogDeprecatedInitWarning)
|
||||
|
||||
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,
|
||||
)
|
||||
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,
|
||||
attributes=event.attributes,
|
||||
)
|
||||
self._logger.emit(log_record)
|
||||
|
||||
|
||||
@deprecated(
|
||||
"You should use `LoggerProvider` instead. "
|
||||
"Deprecated since version 1.39.0 and will be removed in a future release."
|
||||
)
|
||||
class EventLoggerProvider(APIEventLoggerProvider):
|
||||
def __init__(self, logger_provider: Optional[LoggerProvider] = None):
|
||||
self._logger_provider = logger_provider or get_logger_provider()
|
||||
|
||||
@@ -12,27 +12,28 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
from opentelemetry.sdk._logs._internal import (
|
||||
LogData,
|
||||
LogDeprecatedInitWarning,
|
||||
LogDroppedAttributesWarning,
|
||||
Logger,
|
||||
LoggerProvider,
|
||||
LoggingHandler,
|
||||
LogLimits,
|
||||
LogRecord,
|
||||
LogRecordDroppedAttributesWarning,
|
||||
LogRecordLimits,
|
||||
LogRecordProcessor,
|
||||
ReadableLogRecord,
|
||||
ReadWriteLogRecord,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"LogData",
|
||||
"Logger",
|
||||
"LoggerProvider",
|
||||
"LoggingHandler",
|
||||
"LogLimits",
|
||||
"LogRecord",
|
||||
"LogRecordLimits",
|
||||
"LogRecordProcessor",
|
||||
"LogDeprecatedInitWarning",
|
||||
"LogDroppedAttributesWarning",
|
||||
"LogRecordDroppedAttributesWarning",
|
||||
"ReadableLogRecord",
|
||||
"ReadWriteLogRecord",
|
||||
]
|
||||
|
||||
Binary file not shown.
@@ -22,6 +22,7 @@ import logging
|
||||
import threading
|
||||
import traceback
|
||||
import warnings
|
||||
from dataclasses import dataclass, field
|
||||
from os import environ
|
||||
from threading import Lock
|
||||
from time import time_ns
|
||||
@@ -31,8 +32,8 @@ from typing_extensions import deprecated
|
||||
|
||||
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 (
|
||||
LogRecord,
|
||||
NoOpLogger,
|
||||
SeverityNumber,
|
||||
get_logger,
|
||||
@@ -54,13 +55,9 @@ from opentelemetry.semconv.attributes import exception_attributes
|
||||
from opentelemetry.trace import (
|
||||
format_span_id,
|
||||
format_trace_id,
|
||||
get_current_span,
|
||||
)
|
||||
from opentelemetry.trace.span import TraceFlags
|
||||
from opentelemetry.util.types import AnyValue, _ExtendedAttributes
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
_DEFAULT_OTEL_ATTRIBUTE_COUNT_LIMIT = 128
|
||||
_ENV_VALUE_UNSET = ""
|
||||
|
||||
@@ -72,7 +69,7 @@ class BytesEncoder(json.JSONEncoder):
|
||||
return super().default(o)
|
||||
|
||||
|
||||
class LogDroppedAttributesWarning(UserWarning):
|
||||
class LogRecordDroppedAttributesWarning(UserWarning):
|
||||
"""Custom warning to indicate dropped log attributes due to limits.
|
||||
|
||||
This class is used to filter and handle these specific warnings separately
|
||||
@@ -81,22 +78,17 @@ class LogDroppedAttributesWarning(UserWarning):
|
||||
"""
|
||||
|
||||
|
||||
warnings.simplefilter("once", LogDroppedAttributesWarning)
|
||||
warnings.simplefilter("once", LogRecordDroppedAttributesWarning)
|
||||
|
||||
|
||||
class LogDeprecatedInitWarning(UserWarning):
|
||||
"""Custom warning to indicate that deprecated and soon to be deprecated Log classes was used.
|
||||
|
||||
This class is used to filter and handle these specific warnings separately
|
||||
from other warnings, ensuring that they are only shown once without
|
||||
interfering with default user warnings.
|
||||
"""
|
||||
@deprecated(
|
||||
"Use LogRecordDroppedAttributesWarning. Since logs are not stable yet this WILL be removed in future releases."
|
||||
)
|
||||
class LogDroppedAttributesWarning(LogRecordDroppedAttributesWarning):
|
||||
pass
|
||||
|
||||
|
||||
warnings.simplefilter("once", LogDeprecatedInitWarning)
|
||||
|
||||
|
||||
class LogLimits:
|
||||
class LogRecordLimits:
|
||||
"""This class is based on a SpanLimits class in the Tracing module.
|
||||
|
||||
This class represents the limits that should be enforced on recorded data such as events, links, attributes etc.
|
||||
@@ -176,202 +168,125 @@ class LogLimits:
|
||||
return value
|
||||
|
||||
|
||||
class LogRecord(APILogRecord):
|
||||
"""A LogRecord instance represents an event being logged.
|
||||
@deprecated(
|
||||
"Use LogRecordLimits. Since logs are not stable yet this WILL be removed in future releases."
|
||||
)
|
||||
class LogLimits(LogRecordLimits):
|
||||
pass
|
||||
|
||||
LogRecord instances are created and emitted via `Logger`
|
||||
every time something is logged. They contain all the information
|
||||
pertinent to the event being logged.
|
||||
"""
|
||||
|
||||
@overload
|
||||
def __init__(
|
||||
self,
|
||||
timestamp: int | None = None,
|
||||
observed_timestamp: int | None = None,
|
||||
context: Context | None = None,
|
||||
severity_text: str | None = None,
|
||||
severity_number: SeverityNumber | None = None,
|
||||
body: AnyValue | None = None,
|
||||
resource: Resource | None = None,
|
||||
attributes: _ExtendedAttributes | None = None,
|
||||
limits: LogLimits | None = None,
|
||||
event_name: str | None = None,
|
||||
): ...
|
||||
@dataclass(frozen=True)
|
||||
class ReadableLogRecord:
|
||||
"""Readable LogRecord should be kept exactly in-sync with ReadWriteLogRecord, only difference is the frozen=True param."""
|
||||
|
||||
@overload
|
||||
@deprecated(
|
||||
"LogRecord init with `trace_id`, `span_id`, and/or `trace_flags` is deprecated since 1.35.0. Use `context` instead." # noqa: E501
|
||||
)
|
||||
def __init__(
|
||||
self,
|
||||
timestamp: int | None = None,
|
||||
observed_timestamp: int | None = None,
|
||||
trace_id: int | None = None,
|
||||
span_id: int | None = None,
|
||||
trace_flags: TraceFlags | None = None,
|
||||
severity_text: str | None = None,
|
||||
severity_number: SeverityNumber | None = None,
|
||||
body: AnyValue | None = None,
|
||||
resource: Resource | None = None,
|
||||
attributes: _ExtendedAttributes | None = None,
|
||||
limits: LogLimits | None = None,
|
||||
): ...
|
||||
log_record: LogRecord
|
||||
resource: Resource
|
||||
instrumentation_scope: InstrumentationScope | None = None
|
||||
limits: LogRecordLimits | None = None
|
||||
|
||||
def __init__( # pylint:disable=too-many-locals
|
||||
self,
|
||||
timestamp: int | None = None,
|
||||
observed_timestamp: int | None = None,
|
||||
context: Context | None = None,
|
||||
trace_id: int | None = None,
|
||||
span_id: int | None = None,
|
||||
trace_flags: TraceFlags | None = None,
|
||||
severity_text: str | None = None,
|
||||
severity_number: SeverityNumber | None = None,
|
||||
body: AnyValue | None = None,
|
||||
resource: Resource | None = None,
|
||||
attributes: _ExtendedAttributes | None = None,
|
||||
limits: LogLimits | None = None,
|
||||
event_name: str | None = None,
|
||||
):
|
||||
warnings.warn(
|
||||
"LogRecord will be removed in 1.39.0 and replaced by ReadWriteLogRecord and ReadableLogRecord",
|
||||
LogDeprecatedInitWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
if not context:
|
||||
context = get_current()
|
||||
|
||||
if trace_id or span_id or trace_flags:
|
||||
warnings.warn(
|
||||
"LogRecord init with `trace_id`, `span_id`, and/or `trace_flags` is deprecated since 1.35.0. Use `context` instead.",
|
||||
LogDeprecatedInitWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
span = get_current_span(context)
|
||||
span_context = span.get_span_context()
|
||||
|
||||
# Use default LogLimits if none provided
|
||||
if limits is None:
|
||||
limits = LogLimits()
|
||||
|
||||
super().__init__(
|
||||
**{
|
||||
"timestamp": timestamp,
|
||||
"observed_timestamp": observed_timestamp,
|
||||
"context": context,
|
||||
"trace_id": trace_id or span_context.trace_id,
|
||||
"span_id": span_id or span_context.span_id,
|
||||
"trace_flags": trace_flags or span_context.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,
|
||||
extended_attributes=True,
|
||||
),
|
||||
"event_name": event_name,
|
||||
}
|
||||
)
|
||||
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",
|
||||
LogDroppedAttributesWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if not isinstance(other, LogRecord):
|
||||
return NotImplemented
|
||||
return self.__dict__ == other.__dict__
|
||||
@property
|
||||
def dropped_attributes(self) -> int:
|
||||
if isinstance(self.log_record.attributes, BoundedAttributes):
|
||||
return self.log_record.attributes.dropped
|
||||
return 0
|
||||
|
||||
def to_json(self, indent: int | None = 4) -> str:
|
||||
return json.dumps(
|
||||
{
|
||||
"body": self.body,
|
||||
"severity_number": self.severity_number.value
|
||||
if self.severity_number is not None
|
||||
"body": self.log_record.body,
|
||||
"severity_number": self.log_record.severity_number.value
|
||||
if self.log_record.severity_number is not None
|
||||
else None,
|
||||
"severity_text": self.severity_text,
|
||||
"severity_text": self.log_record.severity_text,
|
||||
"attributes": (
|
||||
dict(self.attributes) if bool(self.attributes) else None
|
||||
dict(self.log_record.attributes)
|
||||
if bool(self.log_record.attributes)
|
||||
else None
|
||||
),
|
||||
"dropped_attributes": self.dropped_attributes,
|
||||
"timestamp": ns_to_iso_str(self.timestamp)
|
||||
if self.timestamp is not None
|
||||
"timestamp": ns_to_iso_str(self.log_record.timestamp)
|
||||
if self.log_record.timestamp is not None
|
||||
else None,
|
||||
"observed_timestamp": ns_to_iso_str(self.observed_timestamp),
|
||||
"observed_timestamp": ns_to_iso_str(
|
||||
self.log_record.observed_timestamp
|
||||
),
|
||||
"trace_id": (
|
||||
f"0x{format_trace_id(self.trace_id)}"
|
||||
if self.trace_id is not None
|
||||
f"0x{format_trace_id(self.log_record.trace_id)}"
|
||||
if self.log_record.trace_id is not None
|
||||
else ""
|
||||
),
|
||||
"span_id": (
|
||||
f"0x{format_span_id(self.span_id)}"
|
||||
if self.span_id is not None
|
||||
f"0x{format_span_id(self.log_record.span_id)}"
|
||||
if self.log_record.span_id is not None
|
||||
else ""
|
||||
),
|
||||
"trace_flags": self.trace_flags,
|
||||
"trace_flags": self.log_record.trace_flags,
|
||||
"resource": json.loads(self.resource.to_json()),
|
||||
"event_name": self.event_name if self.event_name else "",
|
||||
"event_name": self.log_record.event_name
|
||||
if self.log_record.event_name
|
||||
else "",
|
||||
},
|
||||
indent=indent,
|
||||
cls=BytesEncoder,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ReadWriteLogRecord:
|
||||
"""A ReadWriteLogRecord instance represents an event being logged.
|
||||
ReadWriteLogRecord instances are created and emitted via `Logger`
|
||||
every time something is logged. They contain all the information
|
||||
pertinent to the event being logged.
|
||||
"""
|
||||
|
||||
log_record: LogRecord
|
||||
resource: Resource | None = Resource.create({})
|
||||
instrumentation_scope: InstrumentationScope | None = None
|
||||
limits: LogRecordLimits = field(default_factory=LogRecordLimits)
|
||||
|
||||
def __post_init__(self):
|
||||
self.log_record.attributes = BoundedAttributes(
|
||||
maxlen=self.limits.max_attributes,
|
||||
attributes=self.log_record.attributes
|
||||
if self.log_record.attributes
|
||||
else None,
|
||||
immutable=False,
|
||||
max_value_len=self.limits.max_attribute_length,
|
||||
extended_attributes=True,
|
||||
)
|
||||
if self.dropped_attributes > 0:
|
||||
warnings.warn(
|
||||
"Log record attributes were dropped due to limits",
|
||||
LogRecordDroppedAttributesWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if not isinstance(other, ReadWriteLogRecord):
|
||||
return NotImplemented
|
||||
return self.__dict__ == other.__dict__
|
||||
|
||||
@property
|
||||
def dropped_attributes(self) -> int:
|
||||
attributes: BoundedAttributes = cast(
|
||||
BoundedAttributes, self.attributes
|
||||
)
|
||||
if attributes:
|
||||
return attributes.dropped
|
||||
if isinstance(self.log_record.attributes, BoundedAttributes):
|
||||
return self.log_record.attributes.dropped
|
||||
return 0
|
||||
|
||||
@classmethod
|
||||
def _from_api_log_record(
|
||||
cls, *, record: APILogRecord, resource: Resource
|
||||
) -> LogRecord:
|
||||
cls,
|
||||
*,
|
||||
record: LogRecord,
|
||||
resource: Resource,
|
||||
instrumentation_scope: InstrumentationScope | None = None,
|
||||
) -> ReadWriteLogRecord:
|
||||
return cls(
|
||||
timestamp=record.timestamp,
|
||||
observed_timestamp=record.observed_timestamp,
|
||||
context=record.context,
|
||||
trace_id=record.trace_id,
|
||||
span_id=record.span_id,
|
||||
trace_flags=record.trace_flags,
|
||||
severity_text=record.severity_text,
|
||||
severity_number=record.severity_number,
|
||||
body=record.body,
|
||||
attributes=record.attributes,
|
||||
event_name=record.event_name,
|
||||
log_record=record,
|
||||
resource=resource,
|
||||
instrumentation_scope=instrumentation_scope,
|
||||
)
|
||||
|
||||
|
||||
class LogData:
|
||||
"""Readable LogRecord data plus associated InstrumentationLibrary."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
log_record: LogRecord,
|
||||
instrumentation_scope: InstrumentationScope,
|
||||
):
|
||||
warnings.warn(
|
||||
"LogData will be removed in 1.39.0 and replaced by ReadWriteLogRecord and ReadableLogRecord",
|
||||
LogDeprecatedInitWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
self.log_record = log_record
|
||||
self.instrumentation_scope = instrumentation_scope
|
||||
|
||||
|
||||
class LogRecordProcessor(abc.ABC):
|
||||
"""Interface to hook the log record emitting action.
|
||||
|
||||
@@ -381,15 +296,15 @@ class LogRecordProcessor(abc.ABC):
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def on_emit(self, log_data: LogData):
|
||||
"""Emits the `LogData`"""
|
||||
def on_emit(self, log_record: ReadWriteLogRecord):
|
||||
"""Emits the `ReadWriteLogRecord`"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def shutdown(self):
|
||||
"""Called when a :class:`opentelemetry.sdk._logs.Logger` is shutdown"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def force_flush(self, timeout_millis: int = 30000):
|
||||
def force_flush(self, timeout_millis: int = 30000) -> bool:
|
||||
"""Export all the received logs to the configured Exporter that have not yet
|
||||
been exported.
|
||||
|
||||
@@ -425,9 +340,9 @@ class SynchronousMultiLogRecordProcessor(LogRecordProcessor):
|
||||
with self._lock:
|
||||
self._log_record_processors += (log_record_processor,)
|
||||
|
||||
def on_emit(self, log_data: LogData) -> None:
|
||||
def on_emit(self, log_record: ReadWriteLogRecord) -> None:
|
||||
for lp in self._log_record_processors:
|
||||
lp.on_emit(log_data)
|
||||
lp.on_emit(log_record)
|
||||
|
||||
def shutdown(self) -> None:
|
||||
"""Shutdown the log processors one by one"""
|
||||
@@ -499,8 +414,8 @@ class ConcurrentMultiLogRecordProcessor(LogRecordProcessor):
|
||||
for future in futures:
|
||||
future.result()
|
||||
|
||||
def on_emit(self, log_data: LogData):
|
||||
self._submit_and_wait(lambda lp: lp.on_emit, log_data)
|
||||
def on_emit(self, log_record: ReadWriteLogRecord):
|
||||
self._submit_and_wait(lambda lp: lp.on_emit, log_record)
|
||||
|
||||
def shutdown(self):
|
||||
self._submit_and_wait(lambda lp: lp.shutdown)
|
||||
@@ -575,8 +490,8 @@ class LoggingHandler(logging.Handler):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
level=logging.NOTSET,
|
||||
logger_provider=None,
|
||||
level: int = logging.NOTSET,
|
||||
logger_provider: APILoggerProvider | None = None,
|
||||
) -> None:
|
||||
super().__init__(level=level)
|
||||
self._logger_provider = logger_provider or get_logger_provider()
|
||||
@@ -609,7 +524,7 @@ class LoggingHandler(logging.Handler):
|
||||
)
|
||||
return attributes
|
||||
|
||||
def _translate(self, record: logging.LogRecord) -> dict:
|
||||
def _translate(self, record: logging.LogRecord) -> LogRecord:
|
||||
timestamp = int(record.created * 1e9)
|
||||
observered_timestamp = time_ns()
|
||||
attributes = self._get_attributes(record)
|
||||
@@ -643,15 +558,15 @@ class LoggingHandler(logging.Handler):
|
||||
"WARN" if record.levelname == "WARNING" else record.levelname
|
||||
)
|
||||
|
||||
return {
|
||||
"timestamp": timestamp,
|
||||
"observed_timestamp": observered_timestamp,
|
||||
"context": get_current() or None,
|
||||
"severity_text": level_name,
|
||||
"severity_number": severity_number,
|
||||
"body": body,
|
||||
"attributes": attributes,
|
||||
}
|
||||
return LogRecord(
|
||||
timestamp=timestamp,
|
||||
observed_timestamp=observered_timestamp,
|
||||
context=get_current() or None,
|
||||
severity_text=level_name,
|
||||
severity_number=severity_number,
|
||||
body=body,
|
||||
attributes=attributes,
|
||||
)
|
||||
|
||||
def emit(self, record: logging.LogRecord) -> None:
|
||||
"""
|
||||
@@ -661,18 +576,18 @@ class LoggingHandler(logging.Handler):
|
||||
"""
|
||||
logger = get_logger(record.name, logger_provider=self._logger_provider)
|
||||
if not isinstance(logger, NoOpLogger):
|
||||
logger.emit(**self._translate(record))
|
||||
logger.emit(self._translate(record))
|
||||
|
||||
def flush(self) -> None:
|
||||
"""
|
||||
Flushes the logging output. Skip flushing if logging_provider has no force_flush method.
|
||||
"""
|
||||
if hasattr(self._logger_provider, "force_flush") and callable(
|
||||
self._logger_provider.force_flush
|
||||
self._logger_provider.force_flush # type: ignore[reportAttributeAccessIssue]
|
||||
):
|
||||
# This is done in a separate thread to avoid a potential deadlock, for
|
||||
# details see https://github.com/open-telemetry/opentelemetry-python/pull/4636.
|
||||
thread = threading.Thread(target=self._logger_provider.force_flush)
|
||||
thread = threading.Thread(target=self._logger_provider.force_flush) # type: ignore[reportAttributeAccessIssue]
|
||||
thread.start()
|
||||
|
||||
|
||||
@@ -700,9 +615,10 @@ class Logger(APILogger):
|
||||
def resource(self):
|
||||
return self._resource
|
||||
|
||||
@overload
|
||||
# pylint: disable=arguments-differ
|
||||
def emit(
|
||||
self,
|
||||
record: LogRecord | None = None,
|
||||
*,
|
||||
timestamp: int | None = None,
|
||||
observed_timestamp: int | None = None,
|
||||
@@ -712,55 +628,41 @@ class Logger(APILogger):
|
||||
body: AnyValue | None = None,
|
||||
attributes: _ExtendedAttributes | None = None,
|
||||
event_name: str | None = None,
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def emit( # pylint:disable=arguments-differ
|
||||
self,
|
||||
record: APILogRecord,
|
||||
) -> None: ...
|
||||
|
||||
def emit(
|
||||
self,
|
||||
record: APILogRecord | None = None,
|
||||
*,
|
||||
timestamp: int | None = None,
|
||||
observed_timestamp: int | None = None,
|
||||
context: Context | None = None,
|
||||
severity_text: str | None = None,
|
||||
severity_number: SeverityNumber | None = None,
|
||||
body: AnyValue | None = None,
|
||||
attributes: _ExtendedAttributes | None = None,
|
||||
event_name: str | None = None,
|
||||
):
|
||||
"""Emits the :class:`LogData` by associating :class:`LogRecord`
|
||||
and instrumentation info.
|
||||
) -> None:
|
||||
"""Emits the :class:`ReadWriteLogRecord` by setting instrumentation scope
|
||||
and forwarding to the processor.
|
||||
"""
|
||||
|
||||
# silence deprecation warnings from internal users
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", category=LogDeprecatedInitWarning)
|
||||
if not record:
|
||||
record = LogRecord(
|
||||
timestamp=timestamp,
|
||||
observed_timestamp=observed_timestamp,
|
||||
context=context,
|
||||
severity_text=severity_text,
|
||||
severity_number=severity_number,
|
||||
body=body,
|
||||
attributes=attributes,
|
||||
event_name=event_name,
|
||||
resource=self._resource,
|
||||
)
|
||||
elif not isinstance(record, LogRecord):
|
||||
# If a record is provided, use it directly
|
||||
if record is not None:
|
||||
if not isinstance(record, ReadWriteLogRecord):
|
||||
# pylint:disable=protected-access
|
||||
record = LogRecord._from_api_log_record(
|
||||
record=record, resource=self._resource
|
||||
writable_record = ReadWriteLogRecord._from_api_log_record(
|
||||
record=record,
|
||||
resource=self._resource,
|
||||
instrumentation_scope=self._instrumentation_scope,
|
||||
)
|
||||
else:
|
||||
writable_record = record
|
||||
else:
|
||||
# Create a record from individual parameters
|
||||
log_record = LogRecord(
|
||||
timestamp=timestamp,
|
||||
observed_timestamp=observed_timestamp,
|
||||
context=context,
|
||||
severity_number=severity_number,
|
||||
severity_text=severity_text,
|
||||
body=body,
|
||||
attributes=attributes,
|
||||
event_name=event_name,
|
||||
)
|
||||
# pylint:disable=protected-access
|
||||
writable_record = ReadWriteLogRecord._from_api_log_record(
|
||||
record=log_record,
|
||||
resource=self._resource,
|
||||
instrumentation_scope=self._instrumentation_scope,
|
||||
)
|
||||
|
||||
log_data = LogData(record, self._instrumentation_scope)
|
||||
|
||||
self._multi_log_record_processor.on_emit(log_data)
|
||||
self._multi_log_record_processor.on_emit(writable_record)
|
||||
|
||||
|
||||
class LoggerProvider(APILoggerProvider):
|
||||
@@ -831,7 +733,7 @@ class LoggerProvider(APILoggerProvider):
|
||||
version: str | None = None,
|
||||
schema_url: str | None = None,
|
||||
attributes: _ExtendedAttributes | None = None,
|
||||
) -> Logger:
|
||||
) -> APILogger:
|
||||
if self._disabled:
|
||||
return NoOpLogger(
|
||||
name,
|
||||
|
||||
Binary file not shown.
@@ -20,6 +20,8 @@ import sys
|
||||
from os import environ, linesep
|
||||
from typing import IO, Callable, Optional, Sequence
|
||||
|
||||
from typing_extensions import deprecated
|
||||
|
||||
from opentelemetry.context import (
|
||||
_SUPPRESS_INSTRUMENTATION_KEY,
|
||||
attach,
|
||||
@@ -27,9 +29,9 @@ from opentelemetry.context import (
|
||||
set_value,
|
||||
)
|
||||
from opentelemetry.sdk._logs import (
|
||||
LogData,
|
||||
LogRecord,
|
||||
LogRecordProcessor,
|
||||
ReadableLogRecord,
|
||||
ReadWriteLogRecord,
|
||||
)
|
||||
from opentelemetry.sdk._shared_internal import BatchProcessor, DuplicateFilter
|
||||
from opentelemetry.sdk.environment_variables import (
|
||||
@@ -38,6 +40,7 @@ from opentelemetry.sdk.environment_variables import (
|
||||
OTEL_BLRP_MAX_QUEUE_SIZE,
|
||||
OTEL_BLRP_SCHEDULE_DELAY,
|
||||
)
|
||||
from opentelemetry.sdk.resources import Resource
|
||||
|
||||
_DEFAULT_SCHEDULE_DELAY_MILLIS = 5000
|
||||
_DEFAULT_MAX_EXPORT_BATCH_SIZE = 512
|
||||
@@ -50,12 +53,20 @@ _logger = logging.getLogger(__name__)
|
||||
_logger.addFilter(DuplicateFilter())
|
||||
|
||||
|
||||
class LogRecordExportResult(enum.Enum):
|
||||
SUCCESS = 0
|
||||
FAILURE = 1
|
||||
|
||||
|
||||
@deprecated(
|
||||
"Use LogRecordExportResult. Since logs are not stable yet this WILL be removed in future releases."
|
||||
)
|
||||
class LogExportResult(enum.Enum):
|
||||
SUCCESS = 0
|
||||
FAILURE = 1
|
||||
|
||||
|
||||
class LogExporter(abc.ABC):
|
||||
class LogRecordExporter(abc.ABC):
|
||||
"""Interface for exporting logs.
|
||||
Interface to be implemented by services that want to export logs received
|
||||
in their own format.
|
||||
@@ -64,10 +75,12 @@ class LogExporter(abc.ABC):
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def export(self, batch: Sequence[LogData]):
|
||||
def export(
|
||||
self, batch: Sequence[ReadableLogRecord]
|
||||
) -> LogRecordExportResult:
|
||||
"""Exports a batch of logs.
|
||||
Args:
|
||||
batch: The list of `LogData` objects to be exported
|
||||
batch: The list of `ReadableLogRecord` objects to be exported
|
||||
Returns:
|
||||
The result of the export
|
||||
"""
|
||||
@@ -80,8 +93,15 @@ class LogExporter(abc.ABC):
|
||||
"""
|
||||
|
||||
|
||||
class ConsoleLogExporter(LogExporter):
|
||||
"""Implementation of :class:`LogExporter` that prints log records to the
|
||||
@deprecated(
|
||||
"Use LogRecordExporter. Since logs are not stable yet this WILL be removed in future releases."
|
||||
)
|
||||
class LogExporter(LogRecordExporter):
|
||||
pass
|
||||
|
||||
|
||||
class ConsoleLogRecordExporter(LogRecordExporter):
|
||||
"""Implementation of :class:`LogRecordExporter` that prints log records to the
|
||||
console.
|
||||
|
||||
This class can be used for diagnostic purposes. It prints the exported
|
||||
@@ -91,39 +111,59 @@ class ConsoleLogExporter(LogExporter):
|
||||
def __init__(
|
||||
self,
|
||||
out: IO = sys.stdout,
|
||||
formatter: Callable[[LogRecord], str] = lambda record: record.to_json()
|
||||
+ linesep,
|
||||
formatter: Callable[
|
||||
[ReadableLogRecord], str
|
||||
] = lambda record: record.to_json() + linesep,
|
||||
):
|
||||
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[ReadableLogRecord]):
|
||||
for log_record in batch:
|
||||
self.out.write(self.formatter(log_record))
|
||||
self.out.flush()
|
||||
return LogExportResult.SUCCESS
|
||||
return LogRecordExportResult.SUCCESS
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
|
||||
@deprecated(
|
||||
"Use ConsoleLogRecordExporter. Since logs are not stable yet this WILL be removed in future releases."
|
||||
)
|
||||
class ConsoleLogExporter(ConsoleLogRecordExporter):
|
||||
pass
|
||||
|
||||
|
||||
class SimpleLogRecordProcessor(LogRecordProcessor):
|
||||
"""This is an implementation of LogRecordProcessor which passes
|
||||
received logs in the export-friendly LogData representation to the
|
||||
configured LogExporter, as soon as they are emitted.
|
||||
received logs directly to the configured LogRecordExporter, as soon as they are emitted.
|
||||
"""
|
||||
|
||||
def __init__(self, exporter: LogExporter):
|
||||
def __init__(self, exporter: LogRecordExporter):
|
||||
self._exporter = exporter
|
||||
self._shutdown = False
|
||||
|
||||
def on_emit(self, log_data: LogData):
|
||||
def on_emit(self, log_record: ReadWriteLogRecord):
|
||||
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,))
|
||||
# Convert ReadWriteLogRecord to ReadableLogRecord before exporting
|
||||
# Note: resource should not be None at this point as it's set during Logger.emit()
|
||||
resource = (
|
||||
log_record.resource
|
||||
if log_record.resource is not None
|
||||
else Resource.create({})
|
||||
)
|
||||
readable_log_record = ReadableLogRecord(
|
||||
log_record=log_record.log_record,
|
||||
resource=resource,
|
||||
instrumentation_scope=log_record.instrumentation_scope,
|
||||
limits=log_record.limits,
|
||||
)
|
||||
self._exporter.export((readable_log_record,))
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
_logger.exception("Exception while exporting logs.")
|
||||
detach(token)
|
||||
@@ -138,8 +178,7 @@ class SimpleLogRecordProcessor(LogRecordProcessor):
|
||||
|
||||
class BatchLogRecordProcessor(LogRecordProcessor):
|
||||
"""This is an implementation of LogRecordProcessor which creates batches of
|
||||
received logs in the export-friendly LogData representation and
|
||||
send to the configured LogExporter, as soon as they are emitted.
|
||||
received logs and sends them to the configured LogRecordExporter.
|
||||
|
||||
`BatchLogRecordProcessor` is configurable with the following environment
|
||||
variables which correspond to constructor parameters:
|
||||
@@ -154,7 +193,7 @@ class BatchLogRecordProcessor(LogRecordProcessor):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
exporter: LogExporter,
|
||||
exporter: LogRecordExporter,
|
||||
schedule_delay_millis: float | None = None,
|
||||
max_export_batch_size: int | None = None,
|
||||
export_timeout_millis: float | None = None,
|
||||
@@ -191,8 +230,21 @@ class BatchLogRecordProcessor(LogRecordProcessor):
|
||||
"Log",
|
||||
)
|
||||
|
||||
def on_emit(self, log_data: LogData) -> None:
|
||||
return self._batch_processor.emit(log_data)
|
||||
def on_emit(self, log_record: ReadWriteLogRecord) -> None:
|
||||
# Convert ReadWriteLogRecord to ReadableLogRecord before passing to BatchProcessor
|
||||
# Note: resource should not be None at this point as it's set during Logger.emit()
|
||||
resource = (
|
||||
log_record.resource
|
||||
if log_record.resource is not None
|
||||
else Resource.create({})
|
||||
)
|
||||
readable_log_record = ReadableLogRecord(
|
||||
log_record=log_record.log_record,
|
||||
resource=resource,
|
||||
instrumentation_scope=log_record.instrumentation_scope,
|
||||
limits=log_record.limits,
|
||||
)
|
||||
return self._batch_processor.emit(readable_log_record)
|
||||
|
||||
def shutdown(self):
|
||||
return self._batch_processor.shutdown()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -15,12 +15,17 @@
|
||||
import threading
|
||||
import typing
|
||||
|
||||
from opentelemetry.sdk._logs import LogData
|
||||
from opentelemetry.sdk._logs.export import LogExporter, LogExportResult
|
||||
from typing_extensions import deprecated
|
||||
|
||||
from opentelemetry.sdk._logs import ReadableLogRecord
|
||||
from opentelemetry.sdk._logs.export import (
|
||||
LogRecordExporter,
|
||||
LogRecordExportResult,
|
||||
)
|
||||
|
||||
|
||||
class InMemoryLogExporter(LogExporter):
|
||||
"""Implementation of :class:`.LogExporter` that stores logs in memory.
|
||||
class InMemoryLogRecordExporter(LogRecordExporter):
|
||||
"""Implementation of :class:`.LogRecordExporter` that stores logs in memory.
|
||||
|
||||
This class can be used for testing purposes. It stores the exported logs
|
||||
in a list in memory that can be retrieved using the
|
||||
@@ -36,16 +41,25 @@ class InMemoryLogExporter(LogExporter):
|
||||
with self._lock:
|
||||
self._logs.clear()
|
||||
|
||||
def get_finished_logs(self) -> typing.Tuple[LogData, ...]:
|
||||
def get_finished_logs(self) -> typing.Tuple[ReadableLogRecord, ...]:
|
||||
with self._lock:
|
||||
return tuple(self._logs)
|
||||
|
||||
def export(self, batch: typing.Sequence[LogData]) -> LogExportResult:
|
||||
def export(
|
||||
self, batch: typing.Sequence[ReadableLogRecord]
|
||||
) -> LogRecordExportResult:
|
||||
if self._stopped:
|
||||
return LogExportResult.FAILURE
|
||||
return LogRecordExportResult.FAILURE
|
||||
with self._lock:
|
||||
self._logs.extend(batch)
|
||||
return LogExportResult.SUCCESS
|
||||
return LogRecordExportResult.SUCCESS
|
||||
|
||||
def shutdown(self) -> None:
|
||||
self._stopped = True
|
||||
|
||||
|
||||
@deprecated(
|
||||
"Use InMemoryLogRecordExporter. Since logs are not stable yet this WILL be removed in future releases."
|
||||
)
|
||||
class InMemoryLogExporter(InMemoryLogRecordExporter):
|
||||
pass
|
||||
|
||||
@@ -15,21 +15,29 @@
|
||||
from opentelemetry.sdk._logs._internal.export import (
|
||||
BatchLogRecordProcessor,
|
||||
ConsoleLogExporter,
|
||||
ConsoleLogRecordExporter,
|
||||
LogExporter,
|
||||
LogExportResult,
|
||||
LogRecordExporter,
|
||||
LogRecordExportResult,
|
||||
SimpleLogRecordProcessor,
|
||||
)
|
||||
|
||||
# The point module is not in the export directory to avoid a circular import.
|
||||
from opentelemetry.sdk._logs._internal.export.in_memory_log_exporter import (
|
||||
InMemoryLogExporter,
|
||||
InMemoryLogRecordExporter,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"BatchLogRecordProcessor",
|
||||
"ConsoleLogExporter",
|
||||
"ConsoleLogRecordExporter",
|
||||
"LogExporter",
|
||||
"LogRecordExporter",
|
||||
"LogExportResult",
|
||||
"LogRecordExportResult",
|
||||
"SimpleLogRecordProcessor",
|
||||
"InMemoryLogExporter",
|
||||
"InMemoryLogRecordExporter",
|
||||
]
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -145,7 +145,7 @@ class ConsoleMetricExporter(MetricExporter):
|
||||
self,
|
||||
out: IO = stdout,
|
||||
formatter: Callable[
|
||||
["opentelemetry.sdk.metrics.export.MetricsData"], str
|
||||
[MetricsData], str
|
||||
] = lambda metrics_data: metrics_data.to_json() + linesep,
|
||||
preferred_temporality: dict[type, AggregationTemporality]
|
||||
| None = None,
|
||||
@@ -362,7 +362,7 @@ class MetricReader(ABC):
|
||||
@abstractmethod
|
||||
def _receive_metrics(
|
||||
self,
|
||||
metrics_data: "opentelemetry.sdk.metrics.export.MetricsData",
|
||||
metrics_data: MetricsData,
|
||||
timeout_millis: float = 10_000,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
@@ -406,13 +406,11 @@ class InMemoryMetricReader(MetricReader):
|
||||
preferred_aggregation=preferred_aggregation,
|
||||
)
|
||||
self._lock = RLock()
|
||||
self._metrics_data: "opentelemetry.sdk.metrics.export.MetricsData" = (
|
||||
None
|
||||
)
|
||||
self._metrics_data: MetricsData = None
|
||||
|
||||
def get_metrics_data(
|
||||
self,
|
||||
) -> Optional["opentelemetry.sdk.metrics.export.MetricsData"]:
|
||||
) -> Optional[MetricsData]:
|
||||
"""Reads and returns current metrics from the SDK"""
|
||||
with self._lock:
|
||||
self.collect()
|
||||
@@ -422,7 +420,7 @@ class InMemoryMetricReader(MetricReader):
|
||||
|
||||
def _receive_metrics(
|
||||
self,
|
||||
metrics_data: "opentelemetry.sdk.metrics.export.MetricsData",
|
||||
metrics_data: MetricsData,
|
||||
timeout_millis: float = 10_000,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
|
||||
Binary file not shown.
@@ -13,8 +13,10 @@
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
from opentelemetry.sdk.metrics._internal.export import (
|
||||
from opentelemetry.sdk.metrics._internal.aggregation import (
|
||||
AggregationTemporality,
|
||||
)
|
||||
from opentelemetry.sdk.metrics._internal.export import (
|
||||
ConsoleMetricExporter,
|
||||
InMemoryMetricReader,
|
||||
MetricExporter,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -63,7 +63,7 @@ class SpanExporter:
|
||||
|
||||
def export(
|
||||
self, spans: typing.Sequence[ReadableSpan]
|
||||
) -> "SpanExportResult":
|
||||
) -> "SpanExportResult": # pyright: ignore[reportReturnType]
|
||||
"""Exports a batch of telemetry data.
|
||||
|
||||
Args:
|
||||
@@ -79,7 +79,7 @@ class SpanExporter:
|
||||
Called when the SDK is shut down.
|
||||
"""
|
||||
|
||||
def force_flush(self, timeout_millis: int = 30000) -> bool:
|
||||
def force_flush(self, timeout_millis: int = 30000) -> bool: # pyright: ignore[reportReturnType]
|
||||
"""Hint to ensure that the export of any spans the exporter has received
|
||||
prior to the call to ForceFlush SHOULD be completed as soon as possible, preferably
|
||||
before returning from this method.
|
||||
@@ -102,7 +102,7 @@ class SimpleSpanProcessor(SpanProcessor):
|
||||
pass
|
||||
|
||||
def on_end(self, span: ReadableSpan) -> None:
|
||||
if not span.context.trace_flags.sampled:
|
||||
if not (span.context and span.context.trace_flags.sampled):
|
||||
return
|
||||
token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True))
|
||||
try:
|
||||
@@ -188,7 +188,7 @@ class BatchSpanProcessor(SpanProcessor):
|
||||
pass
|
||||
|
||||
def on_end(self, span: ReadableSpan) -> None:
|
||||
if not span.context.trace_flags.sampled:
|
||||
if not (span.context and span.context.trace_flags.sampled):
|
||||
return
|
||||
self._batch_processor.emit(span)
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -17,7 +17,7 @@ from typing import Optional
|
||||
from typing_extensions import deprecated
|
||||
|
||||
from opentelemetry.attributes import BoundedAttributes
|
||||
from opentelemetry.util.types import Attributes
|
||||
from opentelemetry.util.types import Attributes, _ExtendedAttributes
|
||||
|
||||
|
||||
class InstrumentationInfo:
|
||||
@@ -94,7 +94,7 @@ class InstrumentationScope:
|
||||
name: str,
|
||||
version: Optional[str] = None,
|
||||
schema_url: Optional[str] = None,
|
||||
attributes: Optional[Attributes] = None,
|
||||
attributes: Optional[_ExtendedAttributes] = None,
|
||||
) -> None:
|
||||
self._name = name
|
||||
self._version = version
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "1.38.0"
|
||||
__version__ = "1.39.1"
|
||||
|
||||
Reference in New Issue
Block a user