|
18 | 18 | _VALUE: TypeAlias = "_LEAF_VALUE | Sequence[_LEAF_VALUE]" |
19 | 19 |
|
20 | 20 |
|
21 | | -CONTENT_TYPE = "application/json" |
22 | | - |
| 21 | +__all__ = [ |
| 22 | + "CONTENT_TYPE", |
| 23 | + "encode_spans", |
| 24 | +] |
23 | 25 |
|
24 | | -_VALUE_TYPES = { |
25 | | - # NOTE: order matters, for isinstance(True, int). |
26 | | - bool: ("boolValue", bool), |
27 | | - int: ("intValue", str), |
28 | | - float: ("doubleValue", float), |
29 | | - bytes: ("bytesValue", bytes), |
30 | | - str: ("stringValue", str), |
31 | | - Sequence: ( |
32 | | - "arrayValue", |
33 | | - lambda value: {"values": [_value(e) for e in _homogeneous_array(value)]}, |
34 | | - ), |
35 | | - Mapping: ( |
36 | | - "kvlistValue", |
37 | | - lambda value: {"values": [{k: _value(v) for k, v in value.items()}]}, |
38 | | - ), |
39 | | -} |
| 26 | +CONTENT_TYPE = "application/json" |
40 | 27 |
|
41 | 28 |
|
42 | 29 | def encode_spans(spans: Sequence[ReadableSpan]) -> bytes: |
@@ -93,23 +80,32 @@ def _attributes( |
93 | 80 | return rv |
94 | 81 |
|
95 | 82 |
|
96 | | -def _homogeneous_array(value: list[_LEAF_VALUE]) -> list[_LEAF_VALUE]: |
| 83 | +def _ensure_homogeneous(value: Sequence[_LEAF_VALUE]) -> Sequence[_LEAF_VALUE]: |
97 | 84 | # TODO: empty lists are allowed, aren't they? |
98 | 85 | if len(types := {type(v) for v in value}) > 1: |
99 | 86 | raise ValueError(f"Attribute value arrays must be homogeneous, got {types=}") |
100 | 87 | return value |
101 | 88 |
|
102 | 89 |
|
103 | | -def _value(value: _VALUE) -> dict[str, Any]: |
104 | | - # Attribute value can be a primitive type, excluging None... |
105 | | - # protobuf allows bytes, but I think OTLP spec does not? |
106 | | - # protobuf allows k:v pairs, but I think OTLP doesn't. |
107 | | - # TODO: read up the spec and validate the allowed type range. |
108 | | - for klass, (key, post) in _VALUE_TYPES.items(): |
109 | | - if isinstance(value, klass): |
110 | | - return {key: post(value)} |
111 | | - |
112 | | - raise ValueError(f"Cannot convert attribute of {type(value)=}") |
| 90 | +def _value(v: _VALUE) -> dict[str, Any]: |
| 91 | + if isinstance(v, bool): |
| 92 | + return {"boolValue": bool(v)} |
| 93 | + if isinstance(v, int): |
| 94 | + return {"intValue": str(int(v))} |
| 95 | + if isinstance(v, float): |
| 96 | + return {"doubleValue": float(v)} |
| 97 | + if isinstance(v, bytes): |
| 98 | + return { |
| 99 | + "bytesValue": bytes(v) |
| 100 | + } # FIXME this can't be right; gotta encode this somehow |
| 101 | + if isinstance(v, str): |
| 102 | + return {"stringValue": str(v)} |
| 103 | + if isinstance(v, Sequence): |
| 104 | + return {"arrayValue": {"values": [_value(e) for e in _ensure_homogeneous(v)]}} |
| 105 | + if isinstance(v, Mapping): |
| 106 | + return {"kvlistValue": {"values": [{k: _value(vv) for k, vv in v.items()}]}} |
| 107 | + |
| 108 | + raise ValueError(f"Cannot convert attribute value of {type(v)=}") |
113 | 109 |
|
114 | 110 |
|
115 | 111 | def _scope(scope: InstrumentationScope): |
|
0 commit comments