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,59 @@
1
+ from pydantic import BaseModel, ConfigDict, Field
2
+ from otel_declarative.Models.Log.constants import LogFormat
3
+
4
+ # --- 引擎状态模块 ---
5
+
6
+ class ReporterEngineState(BaseModel):
7
+ """
8
+ 结构化记录器引擎运行状态快照模型
9
+
10
+ 职责:
11
+ 1、状态聚合: 封装工厂在不同生命周期阶段的关键运行元数据
12
+ 2、线程安全: 利用 frozen=True 确保快照在读取过程中不可修改
13
+ 3、可观测性: 提供标准 __repr__ 实现, 集中暴露引擎健康度
14
+ """
15
+ model_config = ConfigDict(
16
+ frozen=True,
17
+ )
18
+
19
+ # --- 核心状态属性 ---
20
+ is_ready: bool = Field(
21
+ default=False,
22
+ description="就绪状态标识"
23
+ )
24
+
25
+ active_format: LogFormat = Field(
26
+ default=LogFormat.JSON,
27
+ description="当前日志渲染格式"
28
+ )
29
+
30
+ # 逻辑处理器链的长度 (可用于一致性审计)
31
+ processor_count: int = Field(
32
+ default=0,
33
+ description="已挂载处理器数量"
34
+ )
35
+
36
+ has_async_infra: bool = Field(
37
+ default=False,
38
+ description="是否开启异步写入"
39
+ )
40
+
41
+ def __repr__(self) -> str:
42
+ """
43
+ 提供标准化的状态监测输出
44
+ """
45
+ status: str = "READY" if self.is_ready else "PENDING"
46
+ async_flag: str = "ASYNC" if self.has_async_infra else "SYNC"
47
+ return (
48
+ f"<ReporterEngineState status={status}, format={self.active_format.value}, mode={async_flag}, procs={self.processor_count}>"
49
+ )
50
+
51
+ @classmethod
52
+ def create_initial(cls, _format: LogFormat) -> "ReporterEngineState":
53
+ """
54
+ 构造初始待命状态
55
+
56
+ :param _format: 当前系统配置中预设的日志渲染格式
57
+ :return: 处于未就绪状态的 ReporterEngineState 实例
58
+ """
59
+ return cls(is_ready=False, active_format=_format)
@@ -0,0 +1,202 @@
1
+ import structlog.contextvars
2
+ from typing import Dict, Any, List, Callable
3
+ from pydantic import BaseModel, Field, ConfigDict
4
+ from otel_declarative.Models.Log.constants import ILogProcessor
5
+
6
+ # --- 处理器拓扑模块 ---
7
+
8
+ class InjectionLayer(BaseModel):
9
+ """
10
+ 上下文注入层容器模型
11
+
12
+ 职责:
13
+ 1、聚合封装: 包含所有负责向日志事件中产生新数据的处理器 (TraceID、ServiceMetadata 等)
14
+ 2、语义明确: 明确标识该层级仅负责数据增补, 不涉及键名修改或格式化
15
+ 3、接口隔离: 仅接受符合 InjectionLayer 协议的可调用对象
16
+ """
17
+ model_config = ConfigDict(
18
+ frozen=True,
19
+ arbitrary_types_allowed=True, # 允许 Pydantic 校验 Protocol 类型
20
+ )
21
+
22
+ processors: List[ILogProcessor] = Field(
23
+ default_factory=list,
24
+ description="负责产生新元数据的处理器序列"
25
+ )
26
+
27
+ def as_list(self) -> List[ILogProcessor]:
28
+ """
29
+ 获取原始处理器列表以供 structlog 配置使用
30
+
31
+ :return: 符合 structlog 协议的处理器列表
32
+ """
33
+ return self.processors
34
+
35
+ class RenamingLayer(BaseModel):
36
+ """
37
+ 字段重命名层容器模型
38
+
39
+ 职责:
40
+ 1、单一封装: 包含负责最终 Schema 映射的处理器
41
+ 2、末端约束: 明确标识该层级应位于处理链的末端 (但在渲染之前)
42
+ """
43
+ model_config = ConfigDict(
44
+ frozen=True,
45
+ arbitrary_types_allowed=True, # 允许 Pydantic 校验 Protocol 类型
46
+ )
47
+
48
+ processor: ILogProcessor = Field(
49
+ ...,
50
+ description="负责执行 Schema 映射的处理器"
51
+ )
52
+
53
+ def as_list(self) -> List[ILogProcessor]:
54
+ """
55
+ 获取包装为列表的处理器, 便于链式拼接
56
+
57
+ :return: 包含单个处理器的列表
58
+ """
59
+ return [self.processor]
60
+
61
+ class BaseLayer(BaseModel):
62
+ """
63
+ 基础处理层容器模型
64
+
65
+ 职责:
66
+ 1、预置标准库: 封装 structlog 核心的基础处理器 (Context, Timestamp, Level)
67
+ 2、顺序固化: 确保基础元数据的生成顺序不被干扰
68
+ """
69
+ model_config = ConfigDict(
70
+ frozen=True,
71
+ arbitrary_types_allowed=True,
72
+ )
73
+
74
+ # 使用私有属性存储实际处理器列表, 避免 Pydantic 序列化 lambda 或复杂对象时的潜在问题
75
+ _processors: List[Callable] = [
76
+ structlog.contextvars.merge_contextvars,
77
+ structlog.processors.add_log_level,
78
+ structlog.processors.TimeStamper(fmt="iso"),
79
+ ]
80
+
81
+ def as_list(self) -> List[Callable]:
82
+ """
83
+ 获取基础处理器序列
84
+
85
+ :return: 不可变的基础处理器列表
86
+ """
87
+ return list(self._processors)
88
+
89
+ class NormalizationLayer(BaseModel):
90
+ """
91
+ 内容标准化层容器模型
92
+
93
+ 职责:
94
+ 1、格式统一: 将异常、位置参数等非结构化数据转化为标准字典键
95
+ 2、编码安全: 确保所有内容通过 Unicode 解码
96
+ 3、前置约束: 必须位于 RenamingLayer 前执行
97
+ """
98
+ model_config = ConfigDict(
99
+ frozen=True,
100
+ arbitrary_types_allowed=True
101
+ )
102
+
103
+ _processors: List[Callable] = [
104
+ structlog.processors.format_exc_info,
105
+ structlog.processors.EventRenamer("event"),
106
+ structlog.processors.UnicodeDecoder()
107
+ ]
108
+
109
+ def as_list(self) -> List[Callable]:
110
+ """
111
+ 获取标准化处理器序列
112
+
113
+ :return: 不可变的标准化处理器列表
114
+ """
115
+ return list(self._processors)
116
+
117
+ class ProcessorTopology(BaseModel):
118
+ """
119
+ 日志处理器拓扑结构模型
120
+
121
+ 职责:
122
+ 1、全链路编排: 将松散的处理器容器重构为具有严格时序语义的强类型拓扑对象
123
+ 2、层级隔离: 明确划分基础层、注入层、标准化层与重命名层的边界
124
+ 3、链条组装: 提供标准化的 to_chain() 方法生成最终执行序列
125
+ """
126
+ model_config = ConfigDict(
127
+ frozen=True,
128
+ arbitrary_types_allowed=True, # 允许 Pydantic 校验 Protocol 类型
129
+ )
130
+
131
+ # --- 基础层 (组合关系, 强拥有, 自动初始化) ---
132
+ base_layer: BaseLayer = Field(
133
+ default_factory=BaseLayer,
134
+ description="产生时间戳与日志等级的基础层"
135
+ )
136
+
137
+ # --- 注入层 (聚合关系, 外部注入) ---
138
+ injection_layer: InjectionLayer = Field(
139
+ ...,
140
+ description="负责注入 TraceID 与服务元数据的注入层"
141
+ )
142
+
143
+ # --- 标准化层 (组合关系, 强拥有, 自动初始化) ---
144
+ normalization_layer: NormalizationLayer = Field(
145
+ default_factory=NormalizationLayer,
146
+ description="负责内容清洗与标准化的中间层"
147
+ )
148
+
149
+ # --- 重命名层 (聚合关系, 外部注入) ---
150
+ renaming_layer: RenamingLayer = Field(
151
+ ...,
152
+ description="负责最终 Schema 映射的重命名层"
153
+ )
154
+
155
+ def to_chain(self) -> "ProcessorChain":
156
+ """
157
+ 生成符合 structlog 协议的完整处理器链容器
158
+
159
+ 执行顺序 (Strict Order):
160
+ 1、Base: 准备上下文与元数据 (Time, Level)
161
+ 2、Injection: 注入业务追踪信息 (TraceID, Service)
162
+ 3、Normalization: 生成 event / exception 标准键
163
+ 4、Renaming: 执行最终字段映射
164
+
165
+ :return: 封装后的 ProcessorChain 对象
166
+ """
167
+ chain: List[Callable[[Any, str, Dict[str, Any]], Dict[str, Any]]] = []
168
+
169
+ # 按严格拓扑顺序拼接
170
+ chain.extend(self.base_layer.as_list())
171
+ chain.extend(self.injection_layer.as_list())
172
+ chain.extend(self.normalization_layer.as_list())
173
+ chain.extend(self.renaming_layer.as_list())
174
+
175
+ return ProcessorChain(processors=chain)
176
+
177
+ class ProcessorChain(BaseModel):
178
+ """
179
+ 处理器链最终产物容器模型
180
+
181
+ 职责:
182
+ 1、终态封装: 承载已完成所有拓扑排序与校验、可直接交付给 structlog 的处理器序列
183
+ 2、不可变契约: 确保交付给 structlog.configure 的是一个不可被后续逻辑篡改的原子对象
184
+ 3、类型安全: 明确标识该对象内包含的是符合 Callable[[...], Dict] 协议的处理器列表
185
+ """
186
+ model_config = ConfigDict(
187
+ frozen=True,
188
+ arbitrary_types_allowed=True
189
+ )
190
+
191
+ processors: List[Callable[[Any, str, Dict[str, Any]], Dict[str, Any]]] = Field(
192
+ ...,
193
+ description="已排序的处理器 Callable 列表",
194
+ )
195
+
196
+ def unwrap(self) -> List[Callable]:
197
+ """
198
+ 解包获取原始处理器列表
199
+
200
+ :return: structlog 原生处理器列表
201
+ """
202
+ return self.processors
File without changes
@@ -0,0 +1,135 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Dict, Optional
3
+ from otel_declarative.Interfaces.extractor import IExtractor
4
+ from otel_declarative.Engines.model_registry import ModelRegistry
5
+ from otel_declarative.Engines.path_resolver import PathResolver
6
+ from otel_declarative.Engines.object_hydrator import ObjectHydrator
7
+
8
+ @dataclass(frozen=True)
9
+ class ObservabilityEngineState:
10
+ """
11
+ 观测引擎状态快照容器
12
+
13
+ 职责:
14
+ 1、聚合强耦合组件: 将模型注册中心、解析引擎、装配引擎和提取器实例打包为单一原子单元
15
+ 2、支持无锁切换: 利用 python 的引用赋值原子性, 通过替换该容器实例实现无锁热重载
16
+ 3、保证数据一致性: 确保在任何时刻提取逻辑所使用的模型定义与路径解析逻辑是完全匹配的
17
+ """
18
+ # --- 核心引擎组件 ---
19
+ model_registry: ModelRegistry = field(
20
+ metadata={"description": "负责 DTO 模型类定义的动态检索与管理"}
21
+ )
22
+
23
+ object_hydrator: ObjectHydrator = field(
24
+ metadata={"description": "负责将解析出的原始数据递归装配为强类型的 Pydantic 对象"}
25
+ )
26
+
27
+ path_resolver: PathResolver = field(
28
+ metadata={"description": "负责基于 JMESPath 表达式在业务上下文中检索并转换数据"}
29
+ )
30
+
31
+ # --- 策略分发容器 ---
32
+ extractors: Dict[str, IExtractor] = field(
33
+ default_factory=dict,
34
+ metadata={"description": "逻辑层级到具体提取器实例的映射表"}
35
+ )
36
+
37
+ # --- 运行状态标识 ---
38
+ is_ready: bool = field(
39
+ default=False,
40
+ metadata={"description": "标识当前状态快照是否已完成初始化并可投入生产使用"}
41
+ )
42
+
43
+ def get_extractor_for_layer(self, layer: str) -> Optional[IExtractor]:
44
+ """
45
+ [读操作] 从当前快照中安全获取指定层级的提取器
46
+
47
+ :param layer: 业务层级标识符
48
+ :return: 对应的提取器实例
49
+ """
50
+ if not self.is_ready:
51
+ return None
52
+
53
+ return self.extractors.get(layer)
54
+
55
+ @classmethod
56
+ def create_empty(cls) -> 'ObservabilityEngineState':
57
+ """
58
+ 构造一个处于未就绪状态的初始占位状态对象
59
+
60
+ 职责:
61
+ 1、为 ExtractorFactory 提供系统引导初期的 Null-Object 实例
62
+ 2、采样延迟导入方式加载引擎组件, 避免循环导入
63
+ 3、使用空对象实例填充必填字段, 确保系统在未就绪状态下调用属性时不触发 AttributeError
64
+ 4、锁定 is_ready = False, 令 get_extractor_for_layer 能够正常执行 fail-safe 拦截
65
+
66
+ :return: 处于未就绪状态的 ObservabilityEngineState 实例
67
+ """
68
+ from otel_declarative.Engines.model_registry import ModelRegistry
69
+ from otel_declarative.Engines.object_hydrator import ObjectHydrator
70
+ from otel_declarative.Engines.path_resolver import PathResolver
71
+ from otel_declarative.Engines.converter_registry import ConverterRegistry
72
+ from otel_declarative.settings import ObservabilitySettings
73
+
74
+ # 1、构造基础配置环境
75
+ default_settings: ObservabilitySettings = ObservabilitySettings()
76
+ # 2、构造底层空对象内核
77
+ empty_model_reg: ModelRegistry = ModelRegistry()
78
+ empty_conv_reg: ConverterRegistry = ConverterRegistry(default_settings)
79
+ empty_hydrator: ObjectHydrator = ObjectHydrator(empty_model_reg)
80
+ # 3、构造路径解析器占位符
81
+ empty_resolver: PathResolver = PathResolver(
82
+ converter_registry=empty_conv_reg,
83
+ object_hydrator=empty_hydrator,
84
+ )
85
+ return cls(
86
+ model_registry=empty_model_reg,
87
+ object_hydrator=empty_hydrator,
88
+ path_resolver=empty_resolver,
89
+ extractors={},
90
+ is_ready=False,
91
+ )
92
+
93
+ def __repr__(self) -> str:
94
+ """
95
+ 提供可观测的调试信息
96
+
97
+ :return: 描述当前快照状态的字符串
98
+ """
99
+ status: str = "READY" if self.is_ready else "NOT_READY"
100
+ layers: list[str] = list(self.extractors.keys())
101
+ return f"<ObservabilityEngineState status={status} active_layers={layers}>"
102
+
103
+ def __post_init__(self) -> None:
104
+ """
105
+ 数据一致性后验逻辑, 在 dataclass 实例化完成后自动触发 (由 PEP 557 定义)
106
+
107
+ 职责:
108
+ 1、验证核心引擎组件是否已注入
109
+ 2、在构造函数执行到最后一行, 即将返回实例时, 强制执行组件连通性检查
110
+
111
+ :raises:
112
+ TypeError - 当核心引擎组件类型不匹配时抛出
113
+ ValueError - 当系统处于就绪状态单关键依赖缺失时抛出
114
+ """
115
+ required_components: list = [
116
+ ("model_registry", self.model_registry),
117
+ ("object_hydrator", self.object_hydrator),
118
+ ("path_resolver", self.path_resolver),
119
+ ]
120
+ for name, component in required_components:
121
+ if component is None:
122
+ raise ValueError(f"ObservabilityEngineState 初始化失败: 核心组件 '{name}' 为空")
123
+
124
+ if self.is_ready:
125
+ if not isinstance(self.extractors, dict):
126
+ raise TypeError("ObservabilityEngineState 就绪状态校验失败: 'extractors' 必须是 Dict 类型")
127
+
128
+ if not self.extractors:
129
+ from otel_declarative.Logging.logger_factory import get_child_logger
130
+ _audit_logger = get_child_logger("otel_declarative.Audit", "EngineState")
131
+ _audit_logger.warning(
132
+ f"[otel_declarative Audit] 观测引擎快照已就绪, 但 'extractors' 规则映射表为空"
133
+ f"系统将进入 '基础追踪模式'"
134
+ f"仅会产生标准 OpenTelemetry Span,将无法动态提取和注入业务相关的 Attributes"
135
+ )
@@ -0,0 +1,111 @@
1
+ from typing import Any, Dict, Optional
2
+ from pydantic import BaseModel, Field, ConfigDict, field_validator
3
+
4
+ class FieldMapping(BaseModel):
5
+ """
6
+ 单字段提取映射规则模型
7
+
8
+ 职责:
9
+ 1、定义数据提取的路径契约
10
+ 2、定义路径失效时的回退机制
11
+ 3、声明可选的数据清洗逻辑
12
+ """
13
+ model_config = ConfigDict(
14
+ frozen=True,
15
+ populate_by_name=True,
16
+ extra="ignore"
17
+ )
18
+
19
+ # --- 基础路径提取配置 ---
20
+ path: str = Field(
21
+ ...,
22
+ description="基于 JMESPath 标准的数据提取路径, 以 ExtractionSource 为起始点",
23
+ examples=["args.1.stream_id", "env.POD_NAME"]
24
+ )
25
+ default: Any = Field(
26
+ default=None,
27
+ description="路径解析失效时的默认回退值"
28
+ )
29
+
30
+ # --- 数据转换配置 ---
31
+ converter: Optional[str] = Field(
32
+ default=None,
33
+ description="关联在 ConverterRegistry 中的转换器标识符 (例如: 'to_int', 'to_upper', 'to_bool')"
34
+ )
35
+
36
+ # --- 递归装配配置 ---
37
+ model_name: Optional[str] = Field(
38
+ default=None,
39
+ description="关联在 ModelRegistry 中的自定义 Pydantic 模型类名, 若指定, 解析引擎将执行对象装配逻辑"
40
+ )
41
+
42
+ is_list: bool = Field(
43
+ default=False,
44
+ description="声明提取结果是否为对象列表, 若为 True, 引擎将对列表中的每个字典元素执行模型装配"
45
+ )
46
+
47
+ @field_validator("path")
48
+ @classmethod
49
+ def validate_path_syntax(cls, v: str) -> str:
50
+ """
51
+ 验证器: 确保提取路径不为空且符合基础语法要求
52
+
53
+ :param v: 路径字符串
54
+ :return: 验证后的路径
55
+ :raises: ValueError - 当路径格式非法时抛出
56
+ """
57
+ if not v or not v.strip():
58
+ raise ValueError("提取路径 (path) 不能为空")
59
+
60
+ # TODO: 此处未来可扩展 JMESPath 语法的静态合规性预检查
61
+ return v.strip()
62
+
63
+ def __repr__(self) -> str:
64
+ """
65
+ 提供更具可读性的调试输出格式
66
+ """
67
+ hydration_info = f" -> {self.model_name}" if self.model_name else ""
68
+ list_suffix = "[]" if self.is_list else ""
69
+ return f"<FieldMapping path='{self.path}'{hydration_info}{list_suffix} default={self.default}>"
70
+
71
+ class LayerMappingRules(BaseModel):
72
+ """
73
+ 分层提取规则聚合模型
74
+
75
+ 职责:
76
+ 1、聚合特定业务层级在全生命周期内的观测规则
77
+ 2、分别定义输入阶段和输出阶段的提取契约
78
+ 3、为 ExtractorFactory 提供标准化的配置输入
79
+ """
80
+ model_config = ConfigDict(frozen=True)
81
+
82
+ # 输入规则映射: 键名为 InputSummary 模型中的字段名, 值对应提取规则
83
+ input_rules: Dict[str, FieldMapping] = Field(
84
+ default_factory=dict,
85
+ description="InputSummary 的字段映射配置"
86
+ )
87
+ # 输出规则映射: 键名为 OutputSummary 模型中的字段名, 值位对应的提取规则
88
+ output_rules: Dict[str, FieldMapping] = Field(
89
+ default_factory=dict,
90
+ description="OutputSummary 的字段映射配置"
91
+ )
92
+
93
+ def __repr__(self) -> str:
94
+ """
95
+ 提供更清晰的调试信息
96
+ """
97
+ return f"<LayerMappingRules input_fields={list(self.input_rules.keys())} output_fields={list(self.output_rules.keys())}>"
98
+
99
+ @property
100
+ def has_input_rules(self) -> bool:
101
+ """
102
+ 判定是否存在输入提取定义
103
+ """
104
+ return len(self.input_rules) > 0
105
+
106
+ @property
107
+ def has_output_rules(self) -> bool:
108
+ """
109
+ 判定是否存在输出提取定义
110
+ """
111
+ return len(self.output_rules) > 0
@@ -0,0 +1,104 @@
1
+ from typing import Optional, Any, Dict
2
+ from pydantic import BaseModel, Field, ConfigDict
3
+
4
+ class BaseSummary(BaseModel):
5
+ """
6
+ 观测摘要基础模型
7
+
8
+ 职责:
9
+ 1、为所有派生的摘要 DTO 提供统一的 Pydantic 配置
10
+ 2、强制执行不可变性, 确保观测数据在传递过程中不被篡改
11
+ 3、支持别名映射和前向兼容性
12
+ """
13
+ model_config = ConfigDict(
14
+ populate_by_name=True,
15
+ extra="ignore", # 忽略解析过程中可能多出的冗余字段
16
+ frozen=True
17
+ )
18
+
19
+ def to_otel_attributes(self, prefix: str) -> Dict[str, Any]:
20
+ """
21
+ 将模型数据转换为符合 OpenTelemetry 规范的扁平化属性字典
22
+
23
+ 逻辑:
24
+ 1、将模型序列化为原始字典
25
+ 2、过滤所有 None 值, 避免在 Span 中产生空属性
26
+ 3、为所有键名增加标准化的命名空间前缀
27
+
28
+ :param prefix: 属性命名空间前缀
29
+ :return: 经过前缀化处理的扁平化字典
30
+ """
31
+ raw_data = self.model_dump(exclude_none=True)
32
+ return {f"{prefix}{k}": v for k, v in raw_data.items()}
33
+
34
+ class InputSummary(BaseSummary):
35
+ """
36
+ 输入载体标准化摘要模型
37
+
38
+ 职责:
39
+ 1、承载从业务函数入口提取出的关键上下文
40
+ 2、对应 OTel Span 的初始属性集
41
+ """
42
+ # 业务协议标识
43
+ command: Optional[str] = Field(
44
+ default=None,
45
+ description="业务通信协议定义的标准命令字"
46
+ )
47
+ # 业务唯一标识
48
+ stream_id: Optional[str] = Field(
49
+ default=None,
50
+ description="跨系统流转的唯一业务流标识符"
51
+ )
52
+ # 来源节点标识
53
+ pod_name: str = Field(
54
+ ...,
55
+ description="产生该观测数据的 K8s 计算节点名称",
56
+ min_length=1
57
+ )
58
+ # 数据载体名称
59
+ payload_type: str = Field(
60
+ default="Unknown",
61
+ description="运行时探测到的数据负载 Python 类型名称"
62
+ )
63
+
64
+ def to_otel_attributes(self, prefix: str = "input.") -> Dict[str, Any]:
65
+ """
66
+ 重写父类方法, 锁定 'input.' 前缀语义
67
+
68
+ :param prefix: 默认为 'input.'
69
+ :return: 符合 OTel 规范的输入属性集
70
+ """
71
+ return super().to_otel_attributes(prefix)
72
+
73
+ class OutputSummary(BaseSummary):
74
+ """
75
+ 输出结果标准化摘要模型
76
+
77
+ 职责:
78
+ 1、承载业务逻辑处理完成后的反馈元数据
79
+ 2、对应 OTel Span 结束前的状态补充属性
80
+ """
81
+ # 消息追踪锚点
82
+ message_sha: Optional[str] = Field(
83
+ default=None,
84
+ description="由边车生成的全局唯一消息哈希, 用于全链路 ID 锚定"
85
+ )
86
+ # 处理结果简述
87
+ result_brief: str = Field(
88
+ default="No detail provided",
89
+ description="处理结果的简要描述性信息"
90
+ )
91
+ # 转发状态标识
92
+ is_forwarded: bool = Field(
93
+ default=False,
94
+ description="标识该业务消息是否已成功转发至下游服务"
95
+ )
96
+
97
+ def to_otel_attributes(self, prefix: str = "output.") -> Dict[str, Any]:
98
+ """
99
+ 重写父类方法, 锁定 'output.' 前缀语义
100
+
101
+ :param prefix: 默认为 'output.'
102
+ :return: 符合 OTel 规范的输出属性集
103
+ """
104
+ return super().to_otel_attributes(prefix)
File without changes