Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 101db90

Browse files
authored
Add missing to_json methods (open-telemetry#2722)
* Add missing to_json methods Fixes open-telemetry#2716 * Added resource to_json method * Rename to metrics data * Add to_json to Instrumentation Scope as well Fixes open-telemetry#2716
1 parent 9fbc93b commit 101db90

File tree

7 files changed

+380
-111
lines changed

7 files changed

+380
-111
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.12.0rc1-0.31b0...HEAD)
99

10+
- Add missing `to_json` methods
11+
([#2722](https://github.com/open-telemetry/opentelemetry-python/pull/2722)
1012
- Fix type hints for textmap `Getter` and `Setter`
1113
([#2657](https://github.com/open-telemetry/opentelemetry-python/pull/2657))
1214
- Fix LogEmitterProvider.force_flush hanging randomly

opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/export/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ def __init__(
105105
self,
106106
out: IO = stdout,
107107
formatter: Callable[
108-
["opentelemetry.sdk.metrics.export.Metric"], str
109-
] = lambda metric: metric.to_json()
108+
["opentelemetry.sdk.metrics.export.MetricsData"], str
109+
] = lambda metrics_data: metrics_data.to_json()
110110
+ linesep,
111111
):
112112
self.out = out

opentelemetry-sdk/src/opentelemetry/sdk/metrics/_internal/point.py

Lines changed: 90 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
# pylint: disable=unused-import
1616

1717
from dataclasses import asdict, dataclass
18-
from json import dumps
19-
from typing import Sequence, Union
18+
from json import dumps, loads
19+
from typing import Optional, Sequence, Union
2020

2121
# This kind of import is needed to avoid Sphinx errors.
2222
import opentelemetry.sdk.metrics._internal
@@ -36,6 +36,29 @@ class NumberDataPoint:
3636
time_unix_nano: int
3737
value: Union[int, float]
3838

39+
def to_json(self, indent=4) -> str:
40+
return dumps(asdict(self), indent=indent)
41+
42+
43+
@dataclass(frozen=True)
44+
class HistogramDataPoint:
45+
"""Single data point in a timeseries that describes the time-varying scalar
46+
value of a metric.
47+
"""
48+
49+
attributes: Attributes
50+
start_time_unix_nano: int
51+
time_unix_nano: int
52+
count: int
53+
sum: Union[int, float]
54+
bucket_counts: Sequence[int]
55+
explicit_bounds: Sequence[float]
56+
min: float
57+
max: float
58+
59+
def to_json(self, indent=4) -> str:
60+
return dumps(asdict(self), indent=indent)
61+
3962

4063
@dataclass(frozen=True)
4164
class Sum:
@@ -48,15 +71,17 @@ class Sum:
4871
)
4972
is_monotonic: bool
5073

51-
def to_json(self) -> str:
74+
def to_json(self, indent=4) -> str:
5275
return dumps(
5376
{
54-
"data_points": dumps(
55-
[asdict(data_point) for data_point in self.data_points]
56-
),
77+
"data_points": [
78+
loads(data_point.to_json(indent=indent))
79+
for data_point in self.data_points
80+
],
5781
"aggregation_temporality": self.aggregation_temporality,
5882
"is_monotonic": self.is_monotonic,
59-
}
83+
},
84+
indent=indent,
6085
)
6186

6287

@@ -68,33 +93,18 @@ class Gauge:
6893

6994
data_points: Sequence[NumberDataPoint]
7095

71-
def to_json(self) -> str:
96+
def to_json(self, indent=4) -> str:
7297
return dumps(
7398
{
74-
"data_points": dumps(
75-
[asdict(data_point) for data_point in self.data_points]
76-
)
77-
}
99+
"data_points": [
100+
loads(data_point.to_json(indent=indent))
101+
for data_point in self.data_points
102+
],
103+
},
104+
indent=indent,
78105
)
79106

80107

81-
@dataclass(frozen=True)
82-
class HistogramDataPoint:
83-
"""Single data point in a timeseries that describes the time-varying scalar
84-
value of a metric.
85-
"""
86-
87-
attributes: Attributes
88-
start_time_unix_nano: int
89-
time_unix_nano: int
90-
count: int
91-
sum: Union[int, float]
92-
bucket_counts: Sequence[int]
93-
explicit_bounds: Sequence[float]
94-
min: float
95-
max: float
96-
97-
98108
@dataclass(frozen=True)
99109
class Histogram:
100110
"""Represents the type of a metric that is calculated by aggregating as a
@@ -105,14 +115,16 @@ class Histogram:
105115
"opentelemetry.sdk.metrics.export.AggregationTemporality"
106116
)
107117

108-
def to_json(self) -> str:
118+
def to_json(self, indent=4) -> str:
109119
return dumps(
110120
{
111-
"data_points": dumps(
112-
[asdict(data_point) for data_point in self.data_points]
113-
),
121+
"data_points": [
122+
loads(data_point.to_json(indent=indent))
123+
for data_point in self.data_points
124+
],
114125
"aggregation_temporality": self.aggregation_temporality,
115-
}
126+
},
127+
indent=indent,
116128
)
117129

118130

@@ -126,18 +138,19 @@ class Metric:
126138
exported."""
127139

128140
name: str
129-
description: str
130-
unit: str
141+
description: Optional[str]
142+
unit: Optional[str]
131143
data: DataT
132144

133-
def to_json(self) -> str:
145+
def to_json(self, indent=4) -> str:
134146
return dumps(
135147
{
136148
"name": self.name,
137-
"description": self.description if self.description else "",
138-
"unit": self.unit if self.unit else "",
139-
"data": self.data.to_json(),
140-
}
149+
"description": self.description or "",
150+
"unit": self.unit or "",
151+
"data": loads(self.data.to_json(indent=indent)),
152+
},
153+
indent=indent,
141154
)
142155

143156

@@ -149,6 +162,19 @@ class ScopeMetrics:
149162
metrics: Sequence[Metric]
150163
schema_url: str
151164

165+
def to_json(self, indent=4) -> str:
166+
return dumps(
167+
{
168+
"scope": loads(self.scope.to_json(indent=indent)),
169+
"metrics": [
170+
loads(metric.to_json(indent=indent))
171+
for metric in self.metrics
172+
],
173+
"schema_url": self.schema_url,
174+
},
175+
indent=indent,
176+
)
177+
152178

153179
@dataclass(frozen=True)
154180
class ResourceMetrics:
@@ -158,9 +184,32 @@ class ResourceMetrics:
158184
scope_metrics: Sequence[ScopeMetrics]
159185
schema_url: str
160186

187+
def to_json(self, indent=4) -> str:
188+
return dumps(
189+
{
190+
"resource": loads(self.resource.to_json(indent=indent)),
191+
"scope_metrics": [
192+
loads(scope_metrics.to_json(indent=indent))
193+
for scope_metrics in self.scope_metrics
194+
],
195+
"schema_url": self.schema_url,
196+
},
197+
indent=indent,
198+
)
199+
161200

162201
@dataclass(frozen=True)
163202
class MetricsData:
164203
"""An array of ResourceMetrics"""
165204

166205
resource_metrics: Sequence[ResourceMetrics]
206+
207+
def to_json(self, indent=4) -> str:
208+
return dumps(
209+
{
210+
"resource_metrics": [
211+
loads(resource_metrics.to_json(indent=indent))
212+
for resource_metrics in self.resource_metrics
213+
]
214+
}
215+
)

opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,15 @@ def __hash__(self):
242242
f"{dumps(self._attributes.copy(), sort_keys=True)}|{self._schema_url}"
243243
)
244244

245+
def to_json(self, indent=4) -> str:
246+
return dumps(
247+
{
248+
"attributes": dict(self._attributes),
249+
"schema_url": self._schema_url,
250+
},
251+
indent=indent,
252+
)
253+
245254

246255
_EMPTY_RESOURCE = Resource({})
247256
_DEFAULT_RESOURCE = Resource(

opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
import typing
14+
from json import dumps
15+
from typing import Optional
1516

1617
from deprecated import deprecated
1718

@@ -29,8 +30,8 @@ class InstrumentationInfo:
2930
def __init__(
3031
self,
3132
name: str,
32-
version: typing.Optional[str] = None,
33-
schema_url: typing.Optional[str] = None,
33+
version: Optional[str] = None,
34+
schema_url: Optional[str] = None,
3435
):
3536
self._name = name
3637
self._version = version
@@ -59,11 +60,11 @@ def __lt__(self, value):
5960
)
6061

6162
@property
62-
def schema_url(self) -> typing.Optional[str]:
63+
def schema_url(self) -> Optional[str]:
6364
return self._schema_url
6465

6566
@property
66-
def version(self) -> typing.Optional[str]:
67+
def version(self) -> Optional[str]:
6768
return self._version
6869

6970
@property
@@ -84,8 +85,8 @@ class InstrumentationScope:
8485
def __init__(
8586
self,
8687
name: str,
87-
version: typing.Optional[str] = None,
88-
schema_url: typing.Optional[str] = None,
88+
version: Optional[str] = None,
89+
schema_url: Optional[str] = None,
8990
) -> None:
9091
self._name = name
9192
self._version = version
@@ -116,13 +117,23 @@ def __lt__(self, value: object) -> bool:
116117
)
117118

118119
@property
119-
def schema_url(self) -> typing.Optional[str]:
120+
def schema_url(self) -> Optional[str]:
120121
return self._schema_url
121122

122123
@property
123-
def version(self) -> typing.Optional[str]:
124+
def version(self) -> Optional[str]:
124125
return self._version
125126

126127
@property
127128
def name(self) -> str:
128129
return self._name
130+
131+
def to_json(self, indent=4) -> str:
132+
return dumps(
133+
{
134+
"name": self._name,
135+
"version": self._version,
136+
"schema_url": self._schema_url,
137+
},
138+
indent=indent,
139+
)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from unittest import TestCase
16+
17+
from opentelemetry import metrics
18+
from opentelemetry.sdk.metrics import MeterProvider
19+
from opentelemetry.sdk.metrics.export import (
20+
ConsoleMetricExporter,
21+
PeriodicExportingMetricReader,
22+
)
23+
24+
25+
class TestConsoleExporter(TestCase):
26+
def test_console_exporter(self):
27+
28+
try:
29+
exporter = ConsoleMetricExporter()
30+
reader = PeriodicExportingMetricReader(exporter)
31+
provider = MeterProvider(metric_readers=[reader])
32+
metrics.set_meter_provider(provider)
33+
meter = metrics.get_meter(__name__)
34+
counter = meter.create_counter("test")
35+
counter.add(1)
36+
except Exception as error:
37+
self.fail(f"Unexpected exception {error} raised")

0 commit comments

Comments
 (0)