# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0
import logging
from collections.abc import Mapping, Sequence
from typing import overload
from opentelemetry.exporter.http.transport._base import BaseHTTPTransport
from opentelemetry.exporter.otlp.common.http import (
Compression,
_OTLPHTTPClient,
)
from opentelemetry.exporter.otlp.json.common._internal._log_encoder import (
encode_logs,
)
from opentelemetry.exporter.otlp.json.http._internal import (
_build_transport,
_resolve_compression,
_resolve_endpoint,
_resolve_headers,
_resolve_timeout,
)
from opentelemetry.sdk._logs import ReadableLogRecord
from opentelemetry.sdk._logs.export import (
LogRecordExporter,
LogRecordExportResult,
)
from opentelemetry.sdk._shared_internal import DuplicateFilter
from opentelemetry.sdk.environment_variables import (
OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE,
OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE,
OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY,
OTEL_EXPORTER_OTLP_LOGS_COMPRESSION,
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
OTEL_EXPORTER_OTLP_LOGS_HEADERS,
OTEL_EXPORTER_OTLP_LOGS_TIMEOUT,
)
_DEFAULT_LOGS_EXPORT_PATH = "v1/logs"
_logger = logging.getLogger(__name__)
_logger.addFilter(DuplicateFilter())
[docs]
class OTLPLogExporter(LogRecordExporter):
@overload
def __init__(
self,
endpoint: str | None = None,
certificate_file: str | None = None,
client_key_file: str | None = None,
client_certificate_file: str | None = None,
headers: Mapping[str, str] | None = None,
timeout: float | None = None,
compression: Compression | None = None,
) -> None: ...
@overload
def __init__(
self,
endpoint: str | None = None,
certificate_file: None = None,
client_key_file: None = None,
client_certificate_file: None = None,
headers: Mapping[str, str] | None = None,
timeout: float | None = None,
compression: Compression | None = None,
*,
_transport: BaseHTTPTransport,
) -> None: ...
def __init__(
self,
endpoint: str | None = None,
certificate_file: str | None = None,
client_key_file: str | None = None,
client_certificate_file: str | None = None,
headers: Mapping[str, str] | None = None,
timeout: float | None = None,
compression: Compression | None = None,
*,
_transport: BaseHTTPTransport | None = None,
) -> None:
"""OTLP HTTP JSON log exporter.
Args:
endpoint: Full URL of the OTLP/HTTP signal endpoint, including the signal
path. Example: ``http://collector:4318/v1/logs``. For a base URL without a
signal path, set the ``OTEL_EXPORTER_OTLP_ENDPOINT`` environment variable.
"""
transport = _transport or _build_transport(
certificate_file,
client_key_file,
client_certificate_file,
OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE,
OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY,
OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE,
)
self._client = _OTLPHTTPClient(
transport=transport,
endpoint=endpoint or _resolve_endpoint(OTEL_EXPORTER_OTLP_LOGS_ENDPOINT, _DEFAULT_LOGS_EXPORT_PATH),
kind="logs",
timeout=timeout if timeout is not None else _resolve_timeout(OTEL_EXPORTER_OTLP_LOGS_TIMEOUT),
compression=compression
if compression is not None
else _resolve_compression(OTEL_EXPORTER_OTLP_LOGS_COMPRESSION),
headers=_resolve_headers(headers, OTEL_EXPORTER_OTLP_LOGS_HEADERS),
logger=_logger,
)
self._shutdown = False
[docs]
def export(self, batch: Sequence[ReadableLogRecord]) -> LogRecordExportResult:
if self._shutdown:
_logger.warning("Exporter already shutdown, ignoring batch")
return LogRecordExportResult.FAILURE
try:
body = encode_logs(batch).to_json().encode()
# pylint: disable-next=broad-exception-caught
except Exception as error:
_logger.error("Failed to encode logs: %s", error)
return LogRecordExportResult.FAILURE
export_result = self._client.export(body)
return LogRecordExportResult.SUCCESS if export_result.success else LogRecordExportResult.FAILURE
[docs]
def shutdown(self) -> None:
if self._shutdown:
_logger.warning("Exporter already shutdown, ignoring call")
return
self._shutdown = True
self._client.shutdown()
# pylint: disable-next=no-self-use
[docs]
def force_flush(self, timeout_millis: int = 10_000) -> bool:
return True