-
Notifications
You must be signed in to change notification settings - Fork 2
/
next_version_intended_usage.py
118 lines (92 loc) · 3.35 KB
/
next_version_intended_usage.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import logging
from dataclasses import dataclass
from uuid import uuid4
from fastapi import FastAPI
_MISSING = object()
from types import ModuleType
class PrototypeAutoInstrument:
def __init__(self, **kwargs):
self.spans = []
self.blocked = False
self.kwargs = kwargs
if '' in self.kwargs:
self.blocked = self.kwargs.pop('')
def __call__(self, thing=_MISSING, /, **kwargs):
# TODO: consider using `@functools.singledispatch` to split up this function
if thing is _MISSING and not kwargs:
print('WARNING!!! empty call pls stop')
return self
if self.kwargs and kwargs:
print('WARNING!!! you should not need to send kwargs multiple times pls stop')
# support adding kwargs multiple times anyway
new_kwargs = self.kwargs.copy() # should it be an error to update kwargs?
new_kwargs.update(kwargs)
# instrument
if thing is not _MISSING:
if self.blocked:
print('WARNING!!! already used, should not instrument')
if isinstance(thing, ModuleType):
print(f'instrumented module={thing}, {new_kwargs=}')
elif isinstance(thing, FastAPI):
print(f'instrumented FastAPI={thing}, {new_kwargs=}')
elif isinstance(thing, type):
print(f'instrumented class={thing}, {new_kwargs=}')
else:
print(f'instrumented {thing=}, {new_kwargs=}')
if self.kwargs:
self.blocked = True
return thing
# just update kwargs
if self.blocked:
print('WARNING!!! already used, should not update kwargs')
new_kwargs[''] = self.blocked
return PrototypeAutoInstrument(**new_kwargs)
def __enter__(self):
if self.blocked:
print('WARNING!!! should not span')
self.spans.append(uuid4())
print(f'(span start) {self.spans[-1]} {self.kwargs=}')
if self.kwargs:
self.blocked = True
return self.spans[-1]
def __exit__(self, exc_type, exc_val, exc_tb):
print(f'(span end) {self.spans[-1]} {self.kwargs=}')
self.spans.pop()
otel = PrototypeAutoInstrument()
if __name__ == '__main__':
# instrumenting a class looks like this
@otel
class SomeClass:
pass
# instrumenting a dataclass is the same
@otel(some_kwarg='some_value')
@dataclass
class SomeOtherClass:
pass
# instrumenting a function uses the same @otel decorator
@otel(asdf=1)
def some_function():
return SomeClass()
# instrumenting a FastAPI app requires some auto-detection
app = otel(FastAPI())
# instrumenting the logging module will look like this
otel(logging, some_bool=True)
# to instrument a span of code, it can be used as a context manager
with otel:
print(1)
# the context manager can be nested and used with arguments
with otel(sampling=0.5):
print(2)
# idk why you need the span, but if there's a use case, we can return the span / span
with otel as span:
print(3, span)
print(4)
print(5)
# just for testing
print(6)
with otel(sampling=0.5, asdf=2):
print(7)
with otel:
print(8)
print(9)
print(10)