63
63
import typing
64
64
from json import dumps
65
65
from os import environ
66
+ from types import ModuleType
67
+ from typing import Dict , List , Optional , Union , cast
66
68
from urllib import parse
67
69
68
70
from opentelemetry .attributes import BoundedAttributes
75
77
from opentelemetry .util ._importlib_metadata import entry_points , version
76
78
from opentelemetry .util .types import AttributeValue
77
79
80
+ psutil : Optional [ModuleType ] = None
81
+
78
82
try :
79
- import psutil
83
+ import psutil as pustil_module
84
+
85
+ pustil = pustil_module
80
86
except ImportError :
81
- psutil = None
87
+ pass
82
88
83
89
LabelValue = AttributeValue
84
90
Attributes = typing .Mapping [str , LabelValue ]
147
153
class Resource :
148
154
"""A Resource is an immutable representation of the entity producing telemetry as Attributes."""
149
155
156
+ _attributes : Dict [
157
+ str , Union [str , int , float , bool ]
158
+ ] # Example: Adjust according to actual expected types
159
+ _schema_url : str
160
+
150
161
def __init__ (
151
162
self , attributes : Attributes , schema_url : typing .Optional [str ] = None
152
163
):
@@ -173,7 +184,7 @@ def create(
173
184
if not attributes :
174
185
attributes = {}
175
186
176
- resource_detectors = []
187
+ resource_detectors : List [ ResourceDetector ] = []
177
188
178
189
resource = _DEFAULT_RESOURCE
179
190
@@ -182,6 +193,7 @@ def create(
182
193
).split ("," )
183
194
184
195
if "otel" not in otel_experimental_resource_detectors :
196
+
185
197
otel_experimental_resource_detectors .append ("otel" )
186
198
187
199
for resource_detector in otel_experimental_resource_detectors :
@@ -193,9 +205,8 @@ def create(
193
205
name = resource_detector .strip (),
194
206
)
195
207
)
196
- ). load ()()
208
+ )
197
209
)
198
-
199
210
resource = get_aggregated_resources (
200
211
resource_detectors , _DEFAULT_RESOURCE
201
212
).merge (Resource (attributes , schema_url ))
@@ -206,7 +217,7 @@ def create(
206
217
PROCESS_EXECUTABLE_NAME , None
207
218
)
208
219
if process_executable_name :
209
- default_service_name += ":" + process_executable_name
220
+ default_service_name += ":" + str ( process_executable_name )
210
221
resource = resource .merge (
211
222
Resource ({SERVICE_NAME : default_service_name }, schema_url )
212
223
)
@@ -218,6 +229,8 @@ def get_empty() -> "Resource":
218
229
219
230
@property
220
231
def attributes (self ) -> Attributes :
232
+ if self ._attributes is None :
233
+ raise ValueError ("Attributes are not set." )
221
234
return self ._attributes
222
235
223
236
@property
@@ -241,7 +254,7 @@ def merge(self, other: "Resource") -> "Resource":
241
254
Returns:
242
255
The newly-created Resource.
243
256
"""
244
- merged_attributes = self .attributes . copy ( )
257
+ merged_attributes = dict ( self .attributes )
245
258
merged_attributes .update (other .attributes )
246
259
247
260
if self .schema_url == "" :
@@ -257,7 +270,6 @@ def merge(self, other: "Resource") -> "Resource":
257
270
other .schema_url ,
258
271
)
259
272
return self
260
-
261
273
return Resource (merged_attributes , schema_url )
262
274
263
275
def __eq__ (self , other : object ) -> bool :
@@ -268,15 +280,15 @@ def __eq__(self, other: object) -> bool:
268
280
and self ._schema_url == other ._schema_url
269
281
)
270
282
271
- def __hash__ (self ):
272
- return hash (
273
- f"{ dumps (self ._attributes .copy (), sort_keys = True )} |{ self ._schema_url } "
274
- )
283
+ def __hash__ (self ) -> int :
284
+ attributes_json = dumps (self ._attributes .copy (), sort_keys = True )
285
+ return hash (f"{ attributes_json } |{ self ._schema_url } " )
275
286
276
- def to_json (self , indent = 4 ) -> str :
287
+ def to_json (self , indent : int = 4 ) -> str :
288
+ attributes = dict (self ._attributes )
277
289
return dumps (
278
290
{
279
- "attributes" : dict ( self . _attributes ) ,
291
+ "attributes" : attributes ,
280
292
"schema_url" : self ._schema_url ,
281
293
},
282
294
indent = indent ,
@@ -294,7 +306,7 @@ def to_json(self, indent=4) -> str:
294
306
295
307
296
308
class ResourceDetector (abc .ABC ):
297
- def __init__ (self , raise_on_error = False ):
309
+ def __init__ (self , raise_on_error : bool = False ) -> None :
298
310
self .raise_on_error = raise_on_error
299
311
300
312
@abc .abstractmethod
@@ -343,7 +355,7 @@ def detect(self) -> "Resource":
343
355
),
344
356
)
345
357
)
346
- _process_pid = os .getpid ()
358
+ _process_pid = str ( os .getpid () )
347
359
_process_executable_name = sys .executable
348
360
_process_executable_path = os .path .dirname (_process_executable_name )
349
361
_process_command = sys .argv [0 ]
@@ -358,23 +370,24 @@ def detect(self) -> "Resource":
358
370
PROCESS_EXECUTABLE_PATH : _process_executable_path ,
359
371
PROCESS_COMMAND : _process_command ,
360
372
PROCESS_COMMAND_LINE : _process_command_line ,
361
- PROCESS_COMMAND_ARGS : _process_command_args ,
373
+ PROCESS_COMMAND_ARGS : "" . join ( _process_command_args ) ,
362
374
}
363
375
if hasattr (os , "getppid" ):
364
376
# pypy3 does not have getppid()
365
- resource_info [PROCESS_PARENT_PID ] = os .getppid ()
377
+ resource_info [PROCESS_PARENT_PID ] = str ( os .getppid () )
366
378
367
379
if psutil is not None :
368
380
process = psutil .Process ()
369
- resource_info [PROCESS_OWNER ] = process .username ()
381
+ username = cast (str , process .username ())
382
+ resource_info [PROCESS_OWNER ] = username
370
383
371
384
return Resource (resource_info )
372
385
373
386
374
387
def get_aggregated_resources (
375
388
detectors : typing .List ["ResourceDetector" ],
376
389
initial_resource : typing .Optional [Resource ] = None ,
377
- timeout = 5 ,
390
+ timeout : int = 5 ,
378
391
) -> "Resource" :
379
392
"""Retrieves resources from detectors in the order that they were passed
380
393
0 commit comments