otel-declarative 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. otel_declarative/Config/__init__.py +0 -0
  2. otel_declarative/Config/extraction_config.py +79 -0
  3. otel_declarative/Engines/Strategies/__init__.py +0 -0
  4. otel_declarative/Engines/Strategies/converter_strategies.py +120 -0
  5. otel_declarative/Engines/__init__.py +0 -0
  6. otel_declarative/Engines/converter_registry.py +140 -0
  7. otel_declarative/Engines/generic_extractor.py +96 -0
  8. otel_declarative/Engines/log_processors.py +191 -0
  9. otel_declarative/Engines/model_registry.py +90 -0
  10. otel_declarative/Engines/object_hydrator.py +126 -0
  11. otel_declarative/Engines/path_resolver.py +111 -0
  12. otel_declarative/Enums/__init__.py +0 -0
  13. otel_declarative/Enums/converter_types.py +42 -0
  14. otel_declarative/Enums/extraction_source.py +19 -0
  15. otel_declarative/Factories/__init__.py +0 -0
  16. otel_declarative/Factories/extractor_factory.py +156 -0
  17. otel_declarative/Infrastructure/__init__.py +0 -0
  18. otel_declarative/Infrastructure/async_log_engine.py +164 -0
  19. otel_declarative/Infrastructure/handlers.py +39 -0
  20. otel_declarative/Interfaces/__init__.py +0 -0
  21. otel_declarative/Interfaces/extractor.py +50 -0
  22. otel_declarative/Logging/__init__.py +0 -0
  23. otel_declarative/Logging/logger_factory.py +185 -0
  24. otel_declarative/Models/Log/__init__.py +0 -0
  25. otel_declarative/Models/Log/constants.py +47 -0
  26. otel_declarative/Models/Log/context.py +105 -0
  27. otel_declarative/Models/Log/mapping.py +94 -0
  28. otel_declarative/Models/Log/state.py +59 -0
  29. otel_declarative/Models/Log/topology.py +202 -0
  30. otel_declarative/Models/__init__.py +0 -0
  31. otel_declarative/Models/engine_states.py +135 -0
  32. otel_declarative/Models/mapping_models.py +111 -0
  33. otel_declarative/Models/summary_models.py +104 -0
  34. otel_declarative/Reporters/__init__.py +0 -0
  35. otel_declarative/Reporters/structured_reporter.py +154 -0
  36. otel_declarative/__init__.py +13 -0
  37. otel_declarative/constants.py +79 -0
  38. otel_declarative/provider.py +217 -0
  39. otel_declarative/settings.py +150 -0
  40. otel_declarative-0.1.2.dist-info/METADATA +72 -0
  41. otel_declarative-0.1.2.dist-info/RECORD +44 -0
  42. otel_declarative-0.1.2.dist-info/WHEEL +5 -0
  43. otel_declarative-0.1.2.dist-info/licenses/LICENSE +21 -0
  44. otel_declarative-0.1.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,154 @@
1
+ import logging
2
+ import structlog
3
+ from typing import List, Any, Callable, Type, cast
4
+ from otel_declarative.Logging.logger_factory import LogConfig
5
+ from otel_declarative.constants import ObservabilityInternalNamespace
6
+ from otel_declarative.Infrastructure.async_log_engine import AsyncInfrastructureRegistry
7
+ from otel_declarative.Engines.log_processors import get_otel_context_injectors, get_field_renamer_processor
8
+ from otel_declarative.Models.Log.topology import ProcessorTopology, InjectionLayer, RenamingLayer, ProcessorChain
9
+ from otel_declarative.Models.Log.state import ReporterEngineState
10
+ from otel_declarative.Models.Log.context import LogContext, StructuredLogSettings
11
+ from otel_declarative.Models.Log.constants import LogFormat
12
+
13
+
14
+ class StructuredReporterFactory:
15
+ """
16
+ 结构化日志工厂
17
+
18
+ 职责:
19
+ 1、配置编排: 聚合运行时配置、服务上下文与 OTel 处理器链
20
+ 2、引擎初始化: 负责 structlog 全局配置的原子化注入
21
+ 3、异步桥接: 协调 AsyncLogInfrastructure 构建非阻塞日志流水线
22
+ 4、记录器分发: 提供符合 structlog 协议的高性能记录器实例
23
+ """
24
+ def __init__(self, settings: StructuredLogSettings, log_context: LogContext, base_log_config: LogConfig):
25
+ """
26
+ :param settings: 结构化日志引擎全局设置模型
27
+ :param log_context: 服务身份元数据上下文
28
+ :param base_log_config: 基础日志配置
29
+ """
30
+ self._settings: StructuredLogSettings = settings
31
+ self._log_context: LogContext = log_context
32
+ self._base_config: LogConfig = base_log_config
33
+ # 初始化引擎状态为 '待命' 快照, 消除离散布尔变量
34
+ self._state: ReporterEngineState = ReporterEngineState.create_initial(_format=settings.log_format)
35
+
36
+ def setup(self) -> None:
37
+ """
38
+ 执行结构化日志系统的全量初始化流
39
+
40
+ [Fix]
41
+ 逻辑:
42
+ 1、原子检查: 确保全局配置仅执行一次
43
+ 2、异步链路预热: 通过 AsyncInfrastructureRegistry 构建非阻塞的 QueueHandler
44
+ 3、2026.01.15 - 逻辑更改 - 流水线拆解与重组:
45
+ - 分别获取上游组件 Context Injectors 与下游组件 Field Renamer
46
+ - 调用 _build_full_processor_chain 执行拓扑排序, 解决 EventRenamer 竞争条件
47
+ 4、配置注入: 将完整的处理器链与物理异步 Sink 绑定至 structlog 全局单例
48
+ 5、状态切换: 原子替换引擎快照, 标记系统就绪
49
+ """
50
+ if self._state.is_ready:
51
+ return
52
+
53
+ # --- 1、构建底层异步 Handler (IoC 桥接 LoggerFactory) ---
54
+ async_handler: logging.Handler = self._build_physical_async_sink()
55
+
56
+ # --- 2、编排全链路观测处理器链 (基于分层容器模型) ---
57
+ injection_layer: InjectionLayer = get_otel_context_injectors(field_mapping=self._settings.field_mapping, log_context=self._log_context)
58
+ renaming_layer: RenamingLayer = get_field_renamer_processor(field_mapping=self._settings.field_mapping)
59
+ topology = ProcessorTopology(injection_layer=injection_layer, renaming_layer=renaming_layer)
60
+ final_chain: ProcessorChain = topology.to_chain()
61
+ processor_list: List[Callable] = final_chain.unwrap()
62
+
63
+ # --- 3、执行底层核心库配置注入 ---
64
+ self._configure_structlog_core(processor_list, async_handler)
65
+
66
+ # --- 4、原子替换状态快照, 确保线程安全 ---
67
+ self._state = ReporterEngineState(
68
+ is_ready=True,
69
+ active_format=self._settings.log_format,
70
+ processor_count=len(processor_list),
71
+ has_async_infra=self._settings.enable_async
72
+ )
73
+
74
+ def get_logger(self, name: str = "otel.declarative") -> structlog.BoundLogger:
75
+ """
76
+ 获取一个预配置完成的结构化记录器实例
77
+
78
+ 提供 Fail-safe 保护: 若引擎未就绪, 将自动触发引导流
79
+
80
+ :parma name: 记录器逻辑名称, 用于在日志中标识模块
81
+ :return: 具备异步能力, 携带 TraceID 与服务元数据的 structlog 记录器
82
+ """
83
+ if not self._state.is_ready:
84
+ self.setup()
85
+
86
+ root_ns = ObservabilityInternalNamespace.DEFAULT_LAYER.value
87
+ if not name.startswith(root_ns):
88
+ namespaced_name = f"{root_ns}.{name}"
89
+ else:
90
+ namespaced_name = name
91
+ return structlog.get_logger(namespaced_name)
92
+
93
+ @property
94
+ def state(self) -> ReporterEngineState:
95
+ """
96
+ 暴露当前引擎的只读运行状态快照
97
+
98
+ :return: ReporterEngineState 实例
99
+ """
100
+ return self._state
101
+
102
+ # --- 内部组件编排逻辑 ---
103
+
104
+ def _build_physical_async_sink(self) -> logging.Handler:
105
+ """
106
+ 协调异步基础设置管理器构建非阻塞输出句柄
107
+
108
+ :return: 配置完成的 QueueHandler 实例
109
+ """
110
+ infra_manager = AsyncInfrastructureRegistry.get_infrastructure(settings=self._settings, log_config=self._base_config)
111
+ return infra_manager.build_async_handler()
112
+
113
+ def _configure_structlog_core(self, processors: List[Callable], sink_handler: logging.Handler) -> None:
114
+ """
115
+ 执行 structlog 全局单例的底层配置注入, 完成 stdlib logging 的桥接
116
+
117
+ :param processors: 已排序并封装的处理器 Callable 列表
118
+ :param sink_handler: 异步消费端 QueueHandler
119
+ """
120
+ # 1、获取并配置统一的业务根 Logger
121
+ root_ns = ObservabilityInternalNamespace.DEFAULT_LAYER.value
122
+ root_business_logger = logging.getLogger(root_ns)
123
+
124
+ # 2、挂载异步 Sink
125
+ root_business_logger.handlers.clear()
126
+ root_business_logger.addHandler(sink_handler)
127
+
128
+ # 3、实施隔离, 禁止向 root logger 冒泡
129
+ root_business_logger.propagate = False
130
+ root_business_logger.setLevel(logging.NOTSET)
131
+
132
+ # 4、根据配置模型选择最终渲染器策略
133
+ renderer: Callable = (
134
+ structlog.processors.JSONRenderer() if self._settings.log_format == LogFormat.JSON
135
+ else structlog.dev.ConsoleRenderer(colors=True)
136
+ )
137
+
138
+ # 3、解包处理器链并注入全局配置
139
+ structlog.configure(
140
+ processors=processors + [renderer],
141
+ # 使用 stdlib 工厂,它会自动将 get_logger("A") 映射为 logging.getLogger("A")
142
+ # 配合 get_logger 方法中的命名空间前缀注入,实现路由闭环
143
+ logger_factory=structlog.stdlib.LoggerFactory(),
144
+ # 消除协议不匹配警告:
145
+ # 强转 stdlib.BoundLogger 以匹配 structlog 严格的 BindableLogger 协议
146
+ wrapper_class=cast(Type[structlog.typing.BindableLogger], cast(Any, structlog.stdlib.BoundLogger)),
147
+ cache_logger_on_first_use=True,
148
+ )
149
+
150
+ def __repr__(self) -> str:
151
+ """
152
+ 提供可监测的工厂状态摘要
153
+ """
154
+ return str(self._state)
@@ -0,0 +1,13 @@
1
+ from otel_declarative.provider import ObservabilityProvider
2
+ from otel_declarative.settings import ObservabilitySettings
3
+ from otel_declarative.Factories.extractor_factory import ExtractorFactory
4
+ from otel_declarative.Reporters.structured_reporter import StructuredReporterFactory
5
+ from otel_declarative.Models.summary_models import BaseSummary
6
+
7
+ __all__ = [
8
+ "ObservabilityProvider",
9
+ "ObservabilitySettings",
10
+ "ExtractorFactory",
11
+ "StructuredReporterFactory",
12
+ "BaseSummary",
13
+ ]
@@ -0,0 +1,79 @@
1
+ from enum import Enum, unique
2
+
3
+ @unique
4
+ class OtelProtocol(str, Enum):
5
+ """
6
+ OpenTelemetry 传输协议枚举
7
+ """
8
+ GRPC = "grpc"
9
+ HTTP = "http"
10
+
11
+ @unique
12
+ class OtelSecurityMode(str, Enum):
13
+ """
14
+ OpenTelemetry 传输安全模式
15
+ """
16
+ # 明文传输, 适合 K8S Pod 间本地通信
17
+ INSECURE = "insecure"
18
+ # 加密传输, 带有证书校验, 适合跨机房或外网
19
+ TLS = "tls"
20
+
21
+ @unique
22
+ class TraceStatus(str, Enum):
23
+ """
24
+ 追踪执行状态枚举
25
+
26
+ 用于标准化 OTel Span 的最终状态标签
27
+ """
28
+ # 业务逻辑正常完成且耗时在 SLA 范围内
29
+ SUCCESS = "success"
30
+ # 捕获到业务逻辑错误或系统级未处理异常
31
+ FAILED = "failed"
32
+ # 业务逻辑虽然成功, 但执行时间超过预设的慢查询阈值
33
+ SLOW = "slow_threshold"
34
+
35
+ @unique
36
+ class TraceStage(str, Enum):
37
+ """
38
+ 追踪生命周期阶段枚举
39
+
40
+ 定义数据路径拦截器在执行过程中的核心拦截点
41
+ """
42
+ # 阶段 1: 拦截器启动阶段, 执行参数捕获
43
+ PRE = "PRE_EXECUTE"
44
+ # 阶段 2: 业务成功返回节点, 执行结果摘要提取
45
+ POST = "POST_EXECUTE"
46
+ # 阶段 3: 异常触发阶段, 执行堆栈跟踪与现场快照记录
47
+ ERROR = "ERROR_EXECUTE"
48
+
49
+ @unique
50
+ class ExtractionSource(str, Enum):
51
+ """
52
+ 声明式提取源枚举
53
+
54
+ 职责:
55
+ 1、定义路径解析引擎在执行 JMEPath 检索时的定义命名空间
56
+ 2、确保声明式 YAML 配置中的提取路径具有统一的根起点
57
+ """
58
+ # 代指业务函数的位置参数列表
59
+ ARGS = "args"
60
+ # 代指业务函数的关键字参数字典
61
+ KWARGS = "kwargs"
62
+ # 代指业务函数执行完成后的返回值对象
63
+ RESULTS = "results"
64
+ # 代指操作系统环境变量空间
65
+ ENV = "env"
66
+ # 代指被探测对象的运行时 Python 类型信息
67
+ TYPE = "type"
68
+
69
+ @unique
70
+ class ObservabilityInternalNamespace(str, Enum):
71
+ """
72
+ 观测引擎内部专用空间枚举
73
+
74
+ 职责: 统一管理系统内部使用的逻辑标识符, 消除魔术字符串
75
+ """
76
+ # structlog 与 stdlib logging 之间的异步桥接节点名称
77
+ LOG_BRIDGE = "structlog.bridge"
78
+ # 默认观测层级名称
79
+ DEFAULT_LAYER = "otel.declarative"
@@ -0,0 +1,217 @@
1
+ import time
2
+ import functools
3
+ import structlog
4
+ from datetime import datetime, timezone
5
+ from typing import Any, Callable, Optional, TypeVar, cast, Dict
6
+ from opentelemetry import trace
7
+ from opentelemetry.trace import Status, StatusCode, Span, Tracer
8
+ from otel_declarative.settings import ObservabilitySettings
9
+ from otel_declarative.constants import TraceStatus, TraceStage
10
+ from otel_declarative.Models.summary_models import InputSummary, OutputSummary
11
+ from otel_declarative.Factories.extractor_factory import ExtractorFactory
12
+ from otel_declarative.Interfaces.extractor import IExtractor
13
+ from otel_declarative.Reporters.structured_reporter import StructuredReporterFactory
14
+
15
+ T = TypeVar("T", bound=Callable[..., Any])
16
+
17
+ class ObservabilityProvider:
18
+ """
19
+ 观测性组件提供者
20
+
21
+ 职责:
22
+ 1、链路编排: 管理 OpenTelemetry Span 的生命周期
23
+ 2、策略映射: 调用 ExtractorFactory 为不同业务层级匹配声明式提取器
24
+ 3、属性注入: 将提取出的强类型摘要数据转换为 Span Attributes
25
+ 4、性能剖析: 自动度量业务函数的执行耗时并执行 SLA 判定
26
+ """
27
+ def __init__(self, settings: ObservabilitySettings, extractor_factory: ExtractorFactory, reporter_factory: StructuredReporterFactory):
28
+ """
29
+ :param settings: 观测性全局配置对象
30
+ :param extractor_factory: 预初始化完成的策略提取器工厂
31
+ :param reporter_factory: 具备异步桥接能力的结构化记录器工厂
32
+ """
33
+ self._settings: ObservabilitySettings = settings
34
+ self._extractor_factory: ExtractorFactory = extractor_factory
35
+ self._reporter_factory: StructuredReporterFactory = reporter_factory
36
+ # 获取标准 OTel Tracker 单例
37
+ self._tracer: Tracer = trace.get_tracer(self._settings.service_name)
38
+ # 初始化基础设施层记录器
39
+ self._infra_logger = self._reporter_factory.get_logger("otel_declarative.Infrastructure")
40
+
41
+ def trace_data_path(self, layer: str) -> Callable[[T], T]:
42
+ """
43
+ 构造数据路径追踪切片的异步装饰器
44
+
45
+ 逻辑:
46
+ 1、透明拦截异步函数调用现场
47
+ 2、自动获取对应层级的结构化 BoundLogger
48
+ 3、管理全生命周期中的 PRE >> EXECUTE >> POST / ERROR 观测流
49
+ 4、自动清理上下文环境
50
+
51
+ :param layer: 逻辑分层标识符 (需在 YAML 配置中定义对应的映射规则)
52
+ :return: 异步函数装饰器
53
+ """
54
+ def decorator(func: T) -> T:
55
+ @functools.wraps(func)
56
+ async def wrapper(*args: Any, **kwargs: Any) -> Any:
57
+ if not self._settings.enable_tracing:
58
+ return await func(*args, **kwargs)
59
+
60
+ # 每次调用前先清理上下文, 防止线程复用污染
61
+ structlog.contextvars.clear_contextvars()
62
+ log = self._reporter_factory.get_logger(layer)
63
+
64
+ # 启动 OTel Span
65
+ # 注: Span 名称约定使用 'Layer.FunctionName' 格式, 以优化 Jaeger 展示
66
+ span_name = f"{layer}.{func.__qualname__}"
67
+ with self._tracer.start_as_current_span(span_name) as span:
68
+ # 执行 PRE 阶段
69
+ extractor: Optional[IExtractor] = self._handle_pre_execute(
70
+ span=span,
71
+ layer=layer,
72
+ args=args,
73
+ kwargs=kwargs,
74
+ log=log
75
+ )
76
+
77
+ start_pref = time.perf_counter()
78
+ try:
79
+ # 执行业务主逻辑
80
+ result = await func(*args, **kwargs)
81
+
82
+ # 执行 POST 阶段
83
+ execution_duration = time.perf_counter() - start_pref
84
+ self._handle_post_execute(
85
+ span=span,
86
+ layer=layer,
87
+ extractor=extractor,
88
+ result=result,
89
+ duration_sec=execution_duration,
90
+ log=log
91
+ )
92
+
93
+ return result
94
+ except Exception as e:
95
+ self._handle_error_execute(
96
+ span=span,
97
+ layer=layer,
98
+ exception=e,
99
+ log=log
100
+ )
101
+ raise e
102
+ finally:
103
+ structlog.contextvars.clear_contextvars()
104
+
105
+ return cast(T, wrapper)
106
+ return decorator
107
+
108
+ def _handle_pre_execute(self, span: Span, layer: str, args: Any, kwargs: Any, log: Any) -> Optional[IExtractor]:
109
+ """
110
+ 处理进入业务函数前的观测逻辑
111
+
112
+ :param span: 当前活跃的 Span 实例
113
+ :param layer: 逻辑层级标识
114
+ :param args: 原始位置参数
115
+ :param kwargs: 原始关键字参数
116
+ :param log: 绑定的结构化记录器实例
117
+ :return: 匹配到的通用提取器实例 (供 POST 阶段复用)
118
+ """
119
+ try:
120
+ # 从工厂获取声明式提取器
121
+ extractor: Optional[IExtractor] = self._extractor_factory.get_extractor(layer)
122
+ if not extractor:
123
+ return None
124
+
125
+ # 执行基于 YAML 规则的数据提取
126
+ input_dto: InputSummary = extractor.extract_input(args, kwargs)
127
+
128
+ # 注入 OTel 属性
129
+ attributes: Dict[str, Any] = input_dto.to_otel_attributes()
130
+ for k, v in attributes.items():
131
+ span.set_attribute(k, v)
132
+ # 将提取的业务上下文绑定至 structlog
133
+ structlog.contextvars.bind_contextvars(**attributes)
134
+ log.info(f"观测切面入口触发", stage=TraceStage.PRE.value, **attributes)
135
+
136
+ # 记录生命周期事件
137
+ span.add_event(TraceStage.PRE.value, {"at": datetime.now(timezone.utc).isoformat()})
138
+ return extractor
139
+ except Exception:
140
+ self._infra_logger.exception(f"观测路径提取失败 [PRE]", layer=layer, stage=TraceStage.PRE.value)
141
+ return None
142
+
143
+ def _handle_post_execute(self, span: Span, layer: str, extractor: Optional[IExtractor], result: Any, duration_sec: float, log: Any) -> None:
144
+ """
145
+ 处理业务成功返回后的观测逻辑
146
+
147
+ :param span: 当前活跃的 Span 实例
148
+ :param layer: 逻辑层级标识
149
+ :param extractor: 之前匹配到的提取器
150
+ :param result: 业务执行结果
151
+ :param duration_sec: 业务逻辑真实执行时长
152
+ :param log: 绑定的结构化记录器实例
153
+ """
154
+ try:
155
+ # 1、提取输出摘要
156
+ output_attributes: Dict[str, Any] = {}
157
+ if extractor:
158
+ output_dto: OutputSummary = extractor.extract_output(result)
159
+ output_attributes = output_dto.to_otel_attributes()
160
+ # 修正: 循环调用单数形式的 set_attribute 以符合 API 签名
161
+ for k, v in output_dto.to_otel_attributes().items():
162
+ span.set_attribute(k, v)
163
+
164
+ # 2、性能画像与 SLA 判定
165
+ duration_ms = duration_sec * 1000
166
+ span.set_attribute("performance.duration_ms", duration_ms)
167
+
168
+ trace_status_value: str
169
+ if duration_sec > self._settings.slow_query_threshold:
170
+ trace_status_value = TraceStatus.SLOW.value
171
+ span.set_attribute("trace.status", TraceStatus.SLOW.value)
172
+ span.set_status(Status(StatusCode.OK, f"SLA Violation: {duration_ms:.2f}ms"))
173
+ else:
174
+ trace_status_value = TraceStatus.SUCCESS.value
175
+ span.set_attribute("trace.status", TraceStatus.SUCCESS.value)
176
+ span.set_status(Status(StatusCode.OK))
177
+
178
+ log.info(
179
+ f"观测切面执行完成",
180
+ stage=TraceStage.POST.value,
181
+ latency=f"{duration_ms:.2f}ms",
182
+ trace_status=trace_status_value,
183
+ **output_attributes,
184
+ )
185
+
186
+
187
+ span.add_event(TraceStage.POST.value, {"latency": f"{duration_ms:.2f}ms"})
188
+ except Exception:
189
+ self._infra_logger.exception(f"观测路径提取失败 [POST]", layer=layer, stage=TraceStage.POST.value)
190
+
191
+ def _handle_error_execute(self, span: Span, layer: str, exception: Exception, log: Any) -> None:
192
+ """
193
+ 处理业务逻辑崩溃时的异常观测逻辑
194
+
195
+ :param span: 当前活跃的 Span 实例
196
+ :param layer: 业务逻辑层级标识
197
+ :param exception: 捕获到的异常对象
198
+ :param log: 绑定的结构化记录器实例
199
+ """
200
+ # 设置 Span 状态为错误, 触发下游报警
201
+ span.set_status(Status(StatusCode.ERROR, str(exception)))
202
+ span.set_attribute("trace.status", TraceStatus.FAILED.value)
203
+ # 自动记录异常堆栈
204
+ span.record_exception(exception)
205
+
206
+ # 记录生命周期事件并附加异常信息
207
+ log.error(
208
+ f"观测切面业务崩溃",
209
+ stage=TraceStage.ERROR.value,
210
+ exception=type(exception).__name__,
211
+ exception_message=str(exception),
212
+ exc_info=True
213
+ )
214
+ span.add_event(TraceStage.ERROR.value, {
215
+ "exception.type": type(exception).__name__,
216
+ "exception.message": str(exception)
217
+ })
@@ -0,0 +1,150 @@
1
+ import os
2
+ import logging
3
+ from typing import Optional, List, Dict
4
+ from pydantic_settings import BaseSettings, SettingsConfigDict
5
+ from pydantic import Field, field_validator, BaseModel, ConfigDict
6
+ from otel_declarative.constants import OtelProtocol, OtelSecurityMode
7
+
8
+ class OtelExporterSettings(BaseModel):
9
+ """
10
+ OpenTelemetry 导出器专用子模型
11
+
12
+ 职责:
13
+ 1、封装 OTLP 导出相关的传输协议、端点与安全配置
14
+ 2、集中管理 TLS 证书路径等敏感信息
15
+ """
16
+ model_config = ConfigDict(frozen=True)
17
+
18
+ endpoint: str = Field(
19
+ default="http://otel-collector.monitoring:4317",
20
+ description="OTLP Collector 的接受端点"
21
+ )
22
+
23
+ protocol: OtelProtocol = Field(
24
+ default=OtelProtocol.GRPC,
25
+ description="传输协议类型: grpc 或 http"
26
+ )
27
+
28
+ security_mode: OtelSecurityMode = Field(
29
+ default=OtelSecurityMode.INSECURE,
30
+ description="传输安全模式: insecure 或 tls"
31
+ )
32
+
33
+ # --- TLS 专用配置 ---
34
+ ca_certificate_path: Optional[str] = Field(
35
+ default=None,
36
+ description="CA 根证书路径, 若开启 TLS 且该值为空, 则使用系统默认 CA 束"
37
+ )
38
+
39
+ client_key_path: Optional[str] = Field(
40
+ default=None,
41
+ description="客户端证书路径 (双向 TLS 认证专用)"
42
+ )
43
+
44
+ # --- OTLP 自定义 Header 支持 ---
45
+ headers: Optional[Dict[str, str]] = Field(
46
+ default_factory=dict,
47
+ description="OTLP 导出器自定义 HTTP Header, 常用于鉴权 (如: {'Authorization': 'Bearer token'})"
48
+ )
49
+
50
+ class ObservabilitySettings(BaseSettings):
51
+ """
52
+ 观测性全局配置对象
53
+
54
+ 职责:
55
+ 1、定义 OpenTelemetry 的基础导出参数
56
+ 2、定义性能判定阈值与采样策略
57
+ 3、定义声明式映射规则文件的存储路径
58
+ """
59
+ # --- 基础配置 ---
60
+ enable_tracing: bool = Field(
61
+ default=True,
62
+ description="全链路追踪全局开关。设置为 False 时,装饰器将进入透传模式,不产生任何 Span 或属性"
63
+ )
64
+ service_name: str = Field(
65
+ default="deepstream-worker-sidecar",
66
+ description="向 OpenTelemetry 注册的服务唯一标识"
67
+ )
68
+
69
+ # --- 性能判定与采样策略 ---
70
+ slow_query_threshold: float = Field(
71
+ default=0.5,
72
+ ge=0.0,
73
+ description="慢查询判定阈值 (s), 当执行耗时超过该值时, TraceStatus 将被标记为 SLOW"
74
+ )
75
+ sampling_rate: float = Field(
76
+ default=1.0,
77
+ ge=0.0,
78
+ le=1.0,
79
+ description="追踪采样率 (0.0 - 1.0), 针对高频元数据路径, 适当调低以优化 CPU/IO"
80
+ )
81
+
82
+ # --- 策略化提取引擎注册表 ---
83
+ mapping_config_path: str = Field(
84
+ default="config/observability_mapping.yaml",
85
+ description="存储声明式观测数据提取映射规则的 YAML 配置文件路径"
86
+ )
87
+
88
+ otel: OtelExporterSettings = Field(
89
+ default_factory=OtelExporterSettings,
90
+ description="OpenTelemetry 传输层详细设置"
91
+ )
92
+
93
+ # --- 第三方专业库集成配置 ---
94
+ enable_dateparser: bool = Field(
95
+ default=True,
96
+ description="是否启用 dateparser 增强时间戳解析能力"
97
+ )
98
+
99
+ enable_humanize: bool = Field(
100
+ default=True,
101
+ description="是否启用 humanize 实现日志数据的可读化转换"
102
+ )
103
+
104
+ use_glom_spec: bool = Field(
105
+ default=True,
106
+ description="是否允许在转换阶段使用 glom 声明式结构转换"
107
+ )
108
+
109
+ # 默认时间时区配置
110
+ default_timezone: str = Field(
111
+ default="UTC",
112
+ description="解析模糊时间字符串时的默认时区"
113
+ )
114
+
115
+ # 模型扫描路径配置
116
+ model_scan_paths: List[str] = Field(
117
+ default=["Core.Infrastructure.otel_declarative.Models"],
118
+ description="解析引擎启动时应自动扫描并注册模型的模块路径列表"
119
+ )
120
+
121
+ # --- 配置模型行为定义 ---
122
+ model_config = SettingsConfigDict(
123
+ env_prefix="OBS_",
124
+ case_sensitive=False,
125
+ frozen=True,
126
+ extra="ignore"
127
+ )
128
+
129
+ @field_validator("mapping_config_path")
130
+ @classmethod
131
+ def validate_mapping_file_exists(cls, v: str) -> str:
132
+ """
133
+ 验证器: 确保声明式映射配置文件在本地文件系统中真实存在
134
+
135
+ :param v: 验证后的文件路径字符串
136
+ :return: 验证后的路径字符串
137
+ """
138
+ if not os.path.isabs(v):
139
+ logging.warning(
140
+ f"[otel_declarative Config] 映射规则路径 '{v}' 不是绝对路径"
141
+ f"在高动态环境 (如 K8S) 下建议使用绝对路径以避免环境歧义"
142
+ )
143
+
144
+ if not os.path.exists(v):
145
+ logging.warning(
146
+ f"[otel_declarative Config] 映射规则文件未找到: '{v}'"
147
+ f"观测引擎将切换至 '零规则' 模式, 仅记录基础 Span 属性"
148
+ )
149
+
150
+ return v
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.4
2
+ Name: otel-declarative
3
+ Version: 0.1.2
4
+ Summary: Industrial-grade, declarative OpenTelemetry instrumentation and structured logging engine for Python.
5
+ Author-email: Your Name <giangminh443836@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 YaoYuanZheng
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/vancer17/otel-declarative.git
29
+ Project-URL: Repository, https://github.com/vancer17/otel-declarative.git
30
+ Project-URL: Issues, https://github.com/vancer17/otel-declarative.git
31
+ Keywords: opentelemetry,observability,tracing,logging,declarative,pydantic,structlog
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.10
37
+ Classifier: Programming Language :: Python :: 3.11
38
+ Classifier: Programming Language :: Python :: 3.12
39
+ Classifier: Topic :: System :: Monitoring
40
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
41
+ Requires-Python: >=3.10
42
+ Description-Content-Type: text/markdown
43
+ License-File: LICENSE
44
+ Requires-Dist: opentelemetry-api>=1.20.0
45
+ Requires-Dist: opentelemetry-sdk>=1.20.0
46
+ Requires-Dist: opentelemetry-exporter-otlp>=1.20.0
47
+ Requires-Dist: pydantic>=2.0.0
48
+ Requires-Dist: pydantic-settings>=2.0.0
49
+ Requires-Dist: structlog>=23.1.0
50
+ Requires-Dist: jmespath>=1.0.0
51
+ Requires-Dist: pyyaml>=6.0
52
+ Requires-Dist: dateparser>=1.1.0
53
+ Requires-Dist: humanize>=4.0.0
54
+ Requires-Dist: glom>=23.0.0
55
+ Provides-Extra: dev
56
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
57
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
58
+ Requires-Dist: types-PyYAML; extra == "dev"
59
+ Requires-Dist: types-requests; extra == "dev"
60
+ Dynamic: license-file
61
+
62
+ # OTel Declarative
63
+
64
+ Industrial-grade, declarative OpenTelemetry instrumentation and structured logging engine for Python.
65
+
66
+ ## Documentation
67
+
68
+ Please visit our [GitHub Repository](https://github.com/vancer17/otel-declarative.git) for full documentation, usage examples, and architecture details.
69
+
70
+ ## Installation
71
+
72
+ pip install otel-declarative