traceable-agent 1.3.0__tar.gz → 2.0.0__tar.gz

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 (56) hide show
  1. {traceable-agent-1.3.0/src/traceable_agent.egg-info → traceable-agent-2.0.0}/PKG-INFO +6 -6
  2. traceable-agent-2.0.0/setup.py +67 -0
  3. {traceable-agent-1.3.0 → traceable-agent-2.0.0/src/traceable_agent.egg-info}/PKG-INFO +6 -6
  4. traceable-agent-2.0.0/src/traceable_agent.egg-info/SOURCES.txt +45 -0
  5. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/src/traceable_agent.egg-info/entry_points.txt +1 -0
  6. traceable-agent-2.0.0/src/traceable_agent.egg-info/requires.txt +28 -0
  7. traceable-agent-2.0.0/src/traceableai/agent.py +186 -0
  8. traceable-agent-2.0.0/src/traceableai/agent_init.py +177 -0
  9. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/src/traceableai/autoinstrumentation/sitecustomize.py +1 -9
  10. traceable-agent-2.0.0/src/traceableai/config/__init__.py +0 -0
  11. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/src/traceableai/config/config.py +11 -10
  12. traceable-agent-2.0.0/src/traceableai/config/config_pb2.py +91 -0
  13. traceable-agent-2.0.0/src/traceableai/config/default.py +54 -0
  14. traceable-agent-2.0.0/src/traceableai/config/environment.py +150 -0
  15. traceable-agent-2.0.0/src/traceableai/constants.py +9 -0
  16. traceable-agent-2.0.0/src/traceableai/custom_logger.py +41 -0
  17. traceable-agent-2.0.0/src/traceableai/env.py +7 -0
  18. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/src/traceableai/filter/__init__.py +6 -2
  19. traceable-agent-2.0.0/src/traceableai/filter/filter.py +18 -0
  20. traceable-agent-2.0.0/src/traceableai/filter/registry.py +42 -0
  21. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/src/traceableai/filter/traceable.py +19 -8
  22. traceable-agent-2.0.0/src/traceableai/instrumentation/__init__.py +263 -0
  23. traceable-agent-2.0.0/src/traceableai/instrumentation/aiohttp/__init__.py +182 -0
  24. traceable-agent-2.0.0/src/traceableai/instrumentation/aws_lambda/__init__.py +199 -0
  25. traceable-agent-2.0.0/src/traceableai/instrumentation/boto/__init__.py +11 -0
  26. traceable-agent-2.0.0/src/traceableai/instrumentation/botocore/__init__.py +11 -0
  27. traceable-agent-2.0.0/src/traceableai/instrumentation/django/__init__.py +64 -0
  28. traceable-agent-2.0.0/src/traceableai/instrumentation/django/django_auto_instrumentation_compat.py +70 -0
  29. traceable-agent-2.0.0/src/traceableai/instrumentation/fast_api/__init__.py +189 -0
  30. traceable-agent-2.0.0/src/traceableai/instrumentation/fast_api/fast_api_auto_instrumentation_compat.py +65 -0
  31. traceable-agent-2.0.0/src/traceableai/instrumentation/flask/__init__.py +183 -0
  32. traceable-agent-2.0.0/src/traceableai/instrumentation/grpc/__init__.py +265 -0
  33. traceable-agent-2.0.0/src/traceableai/instrumentation/instrumentation_definitions.py +99 -0
  34. traceable-agent-2.0.0/src/traceableai/instrumentation/mysql/__init__.py +11 -0
  35. traceable-agent-2.0.0/src/traceableai/instrumentation/postgresql/__init__.py +13 -0
  36. traceable-agent-2.0.0/src/traceableai/instrumentation/requests/__init__.py +34 -0
  37. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/src/traceableai/version.py +1 -1
  38. traceable-agent-1.3.0/setup.py +0 -42
  39. traceable-agent-1.3.0/src/traceable_agent.egg-info/SOURCES.txt +0 -26
  40. traceable-agent-1.3.0/src/traceable_agent.egg-info/requires.txt +0 -4
  41. traceable-agent-1.3.0/src/traceableai/agent.py +0 -77
  42. traceable-agent-1.3.0/src/traceableai/config/__init__.py +0 -5
  43. traceable-agent-1.3.0/src/traceableai/config/default.py +0 -25
  44. traceable-agent-1.3.0/src/traceableai/config/environment.py +0 -54
  45. traceable-agent-1.3.0/src/traceableai/config/traceable_config_pb2.py +0 -539
  46. traceable-agent-1.3.0/src/traceableai/config_wrapper.py +0 -128
  47. traceable-agent-1.3.0/src/traceableai/hypertrace_env_override.py +0 -20
  48. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/MANIFEST.in +0 -0
  49. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/README.md +0 -0
  50. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/pyproject.toml +0 -0
  51. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/setup.cfg +0 -0
  52. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/src/traceable_agent.egg-info/dependency_links.txt +0 -0
  53. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/src/traceable_agent.egg-info/top_level.txt +0 -0
  54. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/src/traceableai/__init__.py +0 -0
  55. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/src/traceableai/autoinstrumentation/__init__.py +0 -0
  56. {traceable-agent-1.3.0 → traceable-agent-2.0.0}/src/traceableai/autoinstrumentation/wrapper.py +0 -0
@@ -1,17 +1,15 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: traceable-agent
3
- Version: 1.3.0
3
+ Version: 2.0.0
4
4
  Summary: Traceable.ai Python Agent
5
5
  Home-page: https://traceable.ai
6
6
  Author: Traceable.ai
7
+ License: UNKNOWN
8
+ Platform: UNKNOWN
7
9
  Classifier: Programming Language :: Python :: 3
8
10
  Classifier: Operating System :: OS Independent
9
- Requires-Python: >=3.7
11
+ Requires-Python: >=3.8
10
12
  Description-Content-Type: text/markdown
11
- Requires-Dist: hypertrace-agent==0.15.0
12
- Requires-Dist: psutil
13
- Requires-Dist: distro==1.6.0
14
- Requires-Dist: cffi
15
13
 
16
14
  # Python Agent
17
15
 
@@ -95,3 +93,5 @@ git submodule update --init --recursive
95
93
  ```
96
94
  - Test applications
97
95
  1. Refer to `docker/test_apps/`.
96
+
97
+
@@ -0,0 +1,67 @@
1
+ # pylint: skip-file
2
+ import os
3
+ from setuptools import setup, find_packages, Extension
4
+
5
+ exec(open('src/traceableai/version.py').read())
6
+
7
+ with open("README.md", "r", encoding="utf-8") as fh:
8
+ long_description = fh.read()
9
+
10
+ setup(
11
+ name="traceable-agent",
12
+ version=__version__,
13
+ author="Traceable.ai",
14
+ description="Traceable.ai Python Agent",
15
+ url="https://traceable.ai",
16
+ classifiers=[
17
+ "Programming Language :: Python :: 3",
18
+ "Operating System :: OS Independent"
19
+ ],
20
+ package_dir={"": "src"},
21
+ packages=find_packages(where="src"),
22
+ include_package_data=True,
23
+ python_requires=">=3.8",
24
+ ext_modules=[
25
+ # this option will let wheel builder know to package c extensions when ran from CI. No effect for source tar installs
26
+ Extension(
27
+ name='traceableai.filter._libtraceable',
28
+ sources=[],
29
+ optional=os.environ.get('CIBUILDWHEEL', '0') != '1'
30
+ )
31
+ ],
32
+ install_requires=[
33
+ "opentelemetry-api==1.26.0",
34
+ "opentelemetry-exporter-otlp==1.26.0",
35
+ "opentelemetry-instrumentation==0.47b0",
36
+ "opentelemetry-instrumentation-aiohttp-client==0.47b0",
37
+ "opentelemetry-instrumentation-boto==0.47b0",
38
+ "opentelemetry-instrumentation-botocore==0.47b0",
39
+ "opentelemetry-instrumentation-wsgi==0.47b0",
40
+ "opentelemetry-instrumentation-fastapi==0.47b0",
41
+ "opentelemetry-instrumentation-flask==0.47b0",
42
+ "opentelemetry-instrumentation-mysql==0.47b0",
43
+ "opentelemetry-instrumentation-psycopg2==0.47b0",
44
+ "opentelemetry-instrumentation-requests==0.47b0",
45
+ "opentelemetry-instrumentation-grpc==0.47b0",
46
+ "opentelemetry-instrumentation-django==0.47b0",
47
+ "opentelemetry-instrumentation-aws-lambda==0.47b0",
48
+ "opentelemetry-propagator-b3==1.26.0",
49
+ "opentelemetry-proto==1.26.0",
50
+ "opentelemetry-sdk==1.26.0",
51
+ "opentelemetry-util-http==0.47b0",
52
+ "google>=3.0.0",
53
+ "pyyaml",
54
+ "protobuf<5",
55
+ "psutil",
56
+ "distro==1.6.0",
57
+ "cffi",
58
+ "setuptools",
59
+ "jaraco.text",
60
+ "platformdirs"
61
+ ],
62
+ entry_points={
63
+ 'console_scripts': [
64
+ 'traceableai-instrument = traceableai.autoinstrumentation.wrapper:run',
65
+ ],
66
+ }
67
+ )
@@ -1,17 +1,15 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: traceable-agent
3
- Version: 1.3.0
3
+ Version: 2.0.0
4
4
  Summary: Traceable.ai Python Agent
5
5
  Home-page: https://traceable.ai
6
6
  Author: Traceable.ai
7
+ License: UNKNOWN
8
+ Platform: UNKNOWN
7
9
  Classifier: Programming Language :: Python :: 3
8
10
  Classifier: Operating System :: OS Independent
9
- Requires-Python: >=3.7
11
+ Requires-Python: >=3.8
10
12
  Description-Content-Type: text/markdown
11
- Requires-Dist: hypertrace-agent==0.15.0
12
- Requires-Dist: psutil
13
- Requires-Dist: distro==1.6.0
14
- Requires-Dist: cffi
15
13
 
16
14
  # Python Agent
17
15
 
@@ -95,3 +93,5 @@ git submodule update --init --recursive
95
93
  ```
96
94
  - Test applications
97
95
  1. Refer to `docker/test_apps/`.
96
+
97
+
@@ -0,0 +1,45 @@
1
+ MANIFEST.in
2
+ README.md
3
+ pyproject.toml
4
+ setup.cfg
5
+ setup.py
6
+ src/traceable_agent.egg-info/PKG-INFO
7
+ src/traceable_agent.egg-info/SOURCES.txt
8
+ src/traceable_agent.egg-info/dependency_links.txt
9
+ src/traceable_agent.egg-info/entry_points.txt
10
+ src/traceable_agent.egg-info/requires.txt
11
+ src/traceable_agent.egg-info/top_level.txt
12
+ src/traceableai/__init__.py
13
+ src/traceableai/agent.py
14
+ src/traceableai/agent_init.py
15
+ src/traceableai/constants.py
16
+ src/traceableai/custom_logger.py
17
+ src/traceableai/env.py
18
+ src/traceableai/version.py
19
+ src/traceableai/autoinstrumentation/__init__.py
20
+ src/traceableai/autoinstrumentation/sitecustomize.py
21
+ src/traceableai/autoinstrumentation/wrapper.py
22
+ src/traceableai/config/__init__.py
23
+ src/traceableai/config/config.py
24
+ src/traceableai/config/config_pb2.py
25
+ src/traceableai/config/default.py
26
+ src/traceableai/config/environment.py
27
+ src/traceableai/filter/__init__.py
28
+ src/traceableai/filter/filter.py
29
+ src/traceableai/filter/registry.py
30
+ src/traceableai/filter/traceable.py
31
+ src/traceableai/instrumentation/__init__.py
32
+ src/traceableai/instrumentation/instrumentation_definitions.py
33
+ src/traceableai/instrumentation/aiohttp/__init__.py
34
+ src/traceableai/instrumentation/aws_lambda/__init__.py
35
+ src/traceableai/instrumentation/boto/__init__.py
36
+ src/traceableai/instrumentation/botocore/__init__.py
37
+ src/traceableai/instrumentation/django/__init__.py
38
+ src/traceableai/instrumentation/django/django_auto_instrumentation_compat.py
39
+ src/traceableai/instrumentation/fast_api/__init__.py
40
+ src/traceableai/instrumentation/fast_api/fast_api_auto_instrumentation_compat.py
41
+ src/traceableai/instrumentation/flask/__init__.py
42
+ src/traceableai/instrumentation/grpc/__init__.py
43
+ src/traceableai/instrumentation/mysql/__init__.py
44
+ src/traceableai/instrumentation/postgresql/__init__.py
45
+ src/traceableai/instrumentation/requests/__init__.py
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
2
  traceableai-instrument = traceableai.autoinstrumentation.wrapper:run
3
+
@@ -0,0 +1,28 @@
1
+ opentelemetry-api==1.26.0
2
+ opentelemetry-exporter-otlp==1.26.0
3
+ opentelemetry-instrumentation==0.47b0
4
+ opentelemetry-instrumentation-aiohttp-client==0.47b0
5
+ opentelemetry-instrumentation-boto==0.47b0
6
+ opentelemetry-instrumentation-botocore==0.47b0
7
+ opentelemetry-instrumentation-wsgi==0.47b0
8
+ opentelemetry-instrumentation-fastapi==0.47b0
9
+ opentelemetry-instrumentation-flask==0.47b0
10
+ opentelemetry-instrumentation-mysql==0.47b0
11
+ opentelemetry-instrumentation-psycopg2==0.47b0
12
+ opentelemetry-instrumentation-requests==0.47b0
13
+ opentelemetry-instrumentation-grpc==0.47b0
14
+ opentelemetry-instrumentation-django==0.47b0
15
+ opentelemetry-instrumentation-aws-lambda==0.47b0
16
+ opentelemetry-propagator-b3==1.26.0
17
+ opentelemetry-proto==1.26.0
18
+ opentelemetry-sdk==1.26.0
19
+ opentelemetry-util-http==0.47b0
20
+ google>=3.0.0
21
+ pyyaml
22
+ protobuf<5
23
+ psutil
24
+ distro==1.6.0
25
+ cffi
26
+ setuptools
27
+ jaraco.text
28
+ platformdirs
@@ -0,0 +1,186 @@
1
+ import os
2
+ import sys
3
+ import threading
4
+ import traceback
5
+
6
+ import distro
7
+
8
+ from traceableai import constants
9
+ from traceableai.agent_init import AgentInit
10
+ from traceableai.config.config import Config
11
+ from traceableai.custom_logger import get_custom_logger
12
+ from traceableai.env import get_env_value
13
+ from traceableai.filter.registry import Registry
14
+ from traceableai.instrumentation.instrumentation_definitions import SUPPORTED_LIBRARIES, get_instrumentation_wrapper, \
15
+ FLASK_KEY, DJANGO_KEY, FAST_API_KEY, LAMBDA
16
+ from traceableai.version import __version__ # pylint:disable=C0413
17
+ logger = get_custom_logger(__name__)
18
+
19
+
20
+ class Agent():
21
+ _instance = None
22
+ _singleton_lock = threading.Lock()
23
+
24
+ def __new__(cls):
25
+ '''constructor'''
26
+ if cls._instance is None:
27
+ with cls._singleton_lock:
28
+ logger.debug('Creating Agent')
29
+ logger.debug('Python version: %s', sys.version)
30
+ logger.debug('Traceable Agent version: %s', __version__)
31
+ cls._instance = super(Agent, cls).__new__(cls)
32
+ else:
33
+ logger.debug('Using existing Agent.')
34
+ return cls._instance
35
+
36
+ def __init__(self):
37
+ self._initialized = False
38
+ if not self._initialized: # pylint: disable=E0203:
39
+ logger.debug('Initializing Agent.')
40
+ if not self.is_enabled():
41
+ return
42
+ try:
43
+ self._config = Config()
44
+ self._init = AgentInit(self._config)
45
+ self._initialized = True
46
+ except Exception as err: # pylint: disable=W0703
47
+ logger.error('Failed to initialize Agent: exception=%s, stacktrace=%s',
48
+ err,
49
+ traceback.format_exc())
50
+ self.is_lambda = False
51
+ logger.debug("Platform: %s", distro.id())
52
+ logger.debug("Platform version: %s", distro.version())
53
+ logger.debug('TraceableAI Agent version: %s', __version__)
54
+ logger.debug("successfully initialized traceableai agent")
55
+
56
+ if hasattr(os, 'register_at_fork'):
57
+ logger.info('Registering after_in_child handler.')
58
+ os.register_at_fork(after_in_child=self.post_fork) # pylint:disable=E1101
59
+
60
+ def post_fork(self):
61
+ logger.info("In post fork hook")
62
+ logger.info("Calling add traceable filter during post fork")
63
+ self._init.post_fork()
64
+ self.add_traceable_filter()
65
+
66
+ def instrument(self, app=None, skip_libraries=None, auto_instrument=False):
67
+ '''used to register applicable instrumentation wrappers'''
68
+ logger.debug("Beginning instrumentation")
69
+ self._init.apply_config(self._config)
70
+
71
+ if skip_libraries is None:
72
+ skip_libraries = []
73
+ if not self.is_initialized():
74
+ logger.debug('agent is not initialized, not instrumenting')
75
+ return
76
+
77
+ for library_key in SUPPORTED_LIBRARIES:
78
+ if library_key in skip_libraries:
79
+ logger.debug('not attempting to instrument %s', library_key)
80
+ continue
81
+ logger.debug("attempting to instrument %s", library_key)
82
+ self._instrument(library_key, app, auto_instrument)
83
+ logger.debug("Complete instrumentation")
84
+
85
+ def _instrument(self, library_key, app=None, auto_instrument=False):
86
+ """only used to allow the deprecated register_x library methods to still work"""
87
+
88
+ wrapper_instance = get_instrumentation_wrapper(library_key)
89
+ if wrapper_instance is None:
90
+ logger.debug("no instrumentation wrapper instance available for %s", library_key)
91
+ return
92
+
93
+ # Flask is a special case compared to rest of instrumentation
94
+ # using hypertrace-instrument we can replace flask class def before app is initialized
95
+ # however during code based instr we wrap the existing app
96
+ # since replacing class def after app is initialized doesnt have an effect
97
+ # the user has to pass the app in to agent.instrument()
98
+ # we could resolve this edge case by instead having users directly add the middleware
99
+ # ex: app = Flask();
100
+ # app = HypertraceMiddleware(App) => this in turn does agent.instrument()
101
+ # + we have ref to app
102
+ if library_key == FLASK_KEY and app is not None:
103
+ wrapper_instance.with_app(app)
104
+
105
+ # since ht sitecustomize pushes the agent to the front of the load path django instrumentation will error
106
+ # when using autoinstrumentation since we need the django app settings loaded to add middleware
107
+ #
108
+ # in order to resolve this if we detect django we wrap the wsgi/asgi app getter
109
+ # and instrument as soon as the app is retrieved(since settings have to be configured
110
+ # before returning loaded app)
111
+ if library_key == DJANGO_KEY and auto_instrument is True:
112
+ from traceableai.instrumentation.django.django_auto_instrumentation_compat import \
113
+ add_django_auto_instr_wrappers # pylint: disable=C0415
114
+ add_django_auto_instr_wrappers(self, wrapper_instance)
115
+ return
116
+
117
+ # For FastAPI we need a handle to the user app before we can instrument fast & inject middleware
118
+ # to make things easier for the user always add the below instrumentation wrappers
119
+ # when FastAPI calls `.setup` take the app and then add instrumentation
120
+ if library_key == FAST_API_KEY:
121
+ from traceableai.instrumentation.fast_api.fast_api_auto_instrumentation_compat import \
122
+ add_fast_api_auto_instr_wrappers # pylint: disable=C0415
123
+ add_fast_api_auto_instr_wrappers(self, wrapper_instance)
124
+ return
125
+
126
+ if library_key == LAMBDA and '_HANDLER' not in os.environ:
127
+ return
128
+ logger.debug("registering library %s with wrapper instance", library_key)
129
+ self.register_library(library_key, wrapper_instance)
130
+
131
+
132
+ def register_library(self, library_name, wrapper_instance):
133
+ """will configure settings on an instrumentation wrapper + apply"""
134
+ logger.debug('attempting to register library instrumentation: %s', library_name)
135
+ try:
136
+ self._init.init_library_instrumentation(library_name, wrapper_instance)
137
+ except Exception as err: # pylint: disable=W0703
138
+ logger.debug(constants.EXCEPTION_MESSAGE, library_name, err, traceback.format_exc())
139
+
140
+ def register_processor(self, processor) -> None: # pylint: disable=R1710
141
+ '''Add additional span exporters + processors'''
142
+ logger.debug('Entering Agent.register_processor().')
143
+ logger.debug("initialized %s", self.is_initialized())
144
+ if not self.is_initialized():
145
+ return None
146
+ return self._init.register_processor(processor)
147
+
148
+
149
+
150
+ def is_enabled(self) -> bool:
151
+ '''Is agent enabled?'''
152
+ enabled = get_env_value('ENABLED')
153
+ if enabled:
154
+ if enabled.lower() == 'false':
155
+ logger.debug("ENABLED is disabled.")
156
+ return False
157
+ return True
158
+
159
+ def is_initialized(self) -> bool:
160
+ '''Is agent initialized - if an agent fails to init we should let the app continue'''
161
+ if not self.is_enabled():
162
+ return False
163
+ if not self._initialized:
164
+ return False
165
+ return True
166
+
167
+
168
+ def add_traceable_filter(self):
169
+ logger.debug("in add_traceable_filter")
170
+ if self.is_lambda:
171
+ logger.info('Not loading blocking extension - currently unsupported in lambda')
172
+ return
173
+ # We need to do a local import so that the extension is not loaded in a parent process
174
+ from traceableai.filter.traceable import Traceable, _LIBTRACEABLE_AVAILABLE # pylint:disable=C0413,C0412,C0415
175
+ if not _LIBTRACEABLE_AVAILABLE:
176
+ logger.info("libtraceable unavailable, skipping filter registration")
177
+ return
178
+ if Config().config.blocking_config.enabled.value is not True:
179
+ logger.info("Not adding libtraceable filter - blocking is not enabled")
180
+ return
181
+ try:
182
+ Registry().register(Traceable)
183
+ logger.debug("successfully initialized traceable filter")
184
+ except Exception as exc: # pylint:disable=W0703
185
+ logger.debug(''.join(traceback.format_exception(None, exc, exc.__traceback__)))
186
+ logger.info("failed to register traceable filter")
@@ -0,0 +1,177 @@
1
+ '''Initialize all the components using configuration from AgentConfig'''
2
+ import os
3
+ import traceback
4
+ import logging
5
+
6
+ from opentelemetry import trace
7
+ from opentelemetry.sdk.trace import TracerProvider
8
+ from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
9
+ from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter as OTLPGrpcSpanExporter
10
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter as OTLPHttpSpanExporter
11
+ # from opentelemetry.exporter.zipkin.proto.http import ZipkinExporter
12
+ from opentelemetry.trace import ProxyTracerProvider
13
+ from opentelemetry.sdk.resources import Resource
14
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
15
+ from traceableai import constants
16
+ from traceableai.config import config_pb2
17
+
18
+ # Initialize logger
19
+ logger = logging.getLogger(__name__) # pylint: disable=C0103
20
+
21
+
22
+ class AgentInit: # pylint: disable=R0902,R0903
23
+ '''Initialize all the OTel components using configuration from AgentConfig'''
24
+
25
+ def __init__(self, agent_config):
26
+ '''constructor'''
27
+ logger.debug('Initializing AgentInit object.')
28
+ self._config = agent_config
29
+
30
+ # Only available in python > 3.7
31
+ # this does prevent user from having to add post fork hooks to their
32
+ # web server config
33
+ if hasattr(os, 'register_at_fork'):
34
+ logger.info('Registering after_in_child handler.')
35
+ os.register_at_fork(after_in_child=self.post_fork) # pylint:disable=E1101
36
+
37
+ def post_fork(self):
38
+ """Used to reinitialize exporter & processors in separate worker processes"""
39
+ self.apply_config(self._config) # pylint:disable=W0212
40
+
41
+ def apply_config(self, agent_config):
42
+ """Initialize various aspects of the agent based on the most recent config"""
43
+ if agent_config:
44
+ self._config = agent_config
45
+
46
+ self.init_trace_provider()
47
+ self.init_propagation()
48
+
49
+ if "TA_ENABLE_CONSOLE_SPAN_EXPORTER" in os.environ:
50
+ self.set_console_span_processor()
51
+ else:
52
+ self.init_exporter()
53
+
54
+
55
+ def init_trace_provider(self) -> None:
56
+ '''Initialize trace provider and set resource attributes.'''
57
+ if isinstance(trace.get_tracer_provider(), ProxyTracerProvider):
58
+ logger.debug("no configured trace provider detected, adding one")
59
+ resource_attributes = {
60
+ "service.name": self._config.config.service_name.value,
61
+ "service.instance.id": os.getpid(),
62
+ "telemetry.sdk.version": constants.TELEMETRY_SDK_VERSION,
63
+ "telemetry.sdk.name": constants.TELEMETRY_SDK_NAME,
64
+ "telemetry.sdk.language": constants.TELEMETRY_SDK_LANGUAGE
65
+ }
66
+ if self._config.config.resource_attributes:
67
+ logger.debug(
68
+ 'Custom attributes found. Adding to resource attributes dict.')
69
+ resource_attributes.update(
70
+ self._config.config.resource_attributes)
71
+ tracer_provider = TracerProvider(
72
+ resource=Resource.create(resource_attributes)
73
+ )
74
+ trace.set_tracer_provider(tracer_provider)
75
+ else:
76
+ logger.debug("tracer provider already configured, "
77
+ "skipping trace provider configuration")
78
+
79
+ def init_exporter(self) -> None:
80
+ """Initialize exporter"""
81
+ reporter_type = self._config.config.reporting.trace_reporter_type
82
+ exporter = self._init_exporter(reporter_type)
83
+ if exporter is None:
84
+ logger.warning("Unable to initialize exporter")
85
+ return
86
+
87
+ span_processor = BatchSpanProcessor(exporter)
88
+ trace.get_tracer_provider().add_span_processor(span_processor)
89
+
90
+ def init_propagation(self) -> None:
91
+ '''Initialize requested context propagation protocols.'''
92
+ propagator_list = []
93
+ for prop_format in self._config.config.propagation_formats:
94
+ if prop_format == config_pb2.PropagationFormat.TRACECONTEXT:
95
+ from opentelemetry.trace.propagation.tracecontext \
96
+ import TraceContextTextMapPropagator # pylint: disable=C0415
97
+ propagator_list += [ TraceContextTextMapPropagator() ]
98
+ logger.debug('Adding TRACECONTEXT trace propagator to list.')
99
+ if prop_format == config_pb2.PropagationFormat.B3:
100
+ from opentelemetry.propagators.b3 import B3MultiFormat # pylint: disable=C0415
101
+ propagator_list += [ B3MultiFormat() ]
102
+ logger.debug('Adding B3 trace propagator to list.')
103
+
104
+ if len(propagator_list) == 0:
105
+ logger.debug('No propagators have been initialized.')
106
+
107
+ logger.debug('propagator_list: %s', str(propagator_list))
108
+ from opentelemetry.propagate import set_global_textmap # pylint: disable=C0415
109
+ from opentelemetry.propagators.composite import CompositePropagator # pylint: disable=C0415
110
+ composite_propagators = CompositePropagator(propagator_list)
111
+ set_global_textmap(composite_propagators)
112
+
113
+ def _set_wrapper_fields(self, wrapper):
114
+ data_cap = self._config.config.data_capture
115
+ wrapper.set_process_request_headers(data_cap.http_headers.request)
116
+ wrapper.set_process_request_body(data_cap.http_body.request)
117
+ wrapper.set_process_response_headers(data_cap.http_headers.response)
118
+ wrapper.set_process_response_body(data_cap.http_body.response)
119
+ wrapper.set_body_max_size(data_cap.body_max_size_bytes)
120
+
121
+ def init_library_instrumentation(self, instrumentation_name, wrapper_instance):
122
+ """used to configure instrumentation wrapper settings + apply instrumentation"""
123
+ logger.debug("Attempting to initialize %s instrumentation", instrumentation_name)
124
+ try:
125
+ self._set_wrapper_fields(wrapper_instance)
126
+ wrapper_instance.instrument()
127
+ except Exception as err: # pylint: disable=W0703
128
+ logger.debug(constants.INST_WRAP_EXCEPTION_MSSG,
129
+ instrumentation_name,
130
+ err,
131
+ traceback.format_exc())
132
+
133
+ def register_processor(self, processor) -> None:
134
+ '''Register additional span exporter + processor'''
135
+ logger.debug('Entering AgentInit.register_processor().')
136
+ trace.get_tracer_provider().add_span_processor(processor)
137
+
138
+ def set_console_span_processor(self) -> None:
139
+ '''Register the console span processor for debugging purposes.'''
140
+ logger.debug('Entering AgentInit.setConsoleSpanProcessor().')
141
+ console_span_exporter = ConsoleSpanExporter(
142
+ service_name=self._config.config.service_name)
143
+ simple_export_span_processor = SimpleSpanProcessor(
144
+ console_span_exporter)
145
+ trace.get_tracer_provider().add_span_processor(simple_export_span_processor)
146
+
147
+ def _init_exporter(self, trace_reporter_type):
148
+ exporter_type = ''
149
+ exporter = None
150
+ try:
151
+ if trace_reporter_type == config_pb2.TraceReporterType.ZIPKIN:
152
+ exporter_type = 'zipkin'
153
+ #exporter = ZipkinExporter(
154
+ # endpoint=self._config.agent_config.reporting.endpoint
155
+ #)
156
+ elif trace_reporter_type == config_pb2.TraceReporterType.OTLP:
157
+ exporter_type = 'otlp'
158
+ exporter = OTLPGrpcSpanExporter(endpoint=self._config.config.reporting.endpoint.value,
159
+ insecure= not self._config.config.reporting.secure.value)
160
+ elif trace_reporter_type == config_pb2.TraceReporterType.OTLP_HTTP:
161
+ exporter_type = 'otlp_http'
162
+ exporter = OTLPHttpSpanExporter(endpoint=self._config.config.reporting.endpoint.value)
163
+
164
+ if exporter:
165
+ logger.info('Initialized %s exporter reporting to `%s`',
166
+ exporter_type,
167
+ self._config.config.reporting.endpoint.value)
168
+ else:
169
+ logger.error("Unknown exporter type `%s`", trace_reporter_type)
170
+
171
+ return exporter
172
+ except Exception as err: # pylint: disable=W0703
173
+ logger.error('Failed to initialize %s exporter: exception=%s, stacktrace=%s',
174
+ exporter_type,
175
+ err,
176
+ traceback.format_exc())
177
+ return None
@@ -1,18 +1,10 @@
1
1
  import os
2
2
 
3
3
  import psutil
4
- # Allow use of TA_ env vars instead of HT_
5
- from hypertrace import env_var_settings
6
-
7
- from traceableai.hypertrace_env_override import add_deprecation_to_ht_env
8
-
9
- env_var_settings.ENV_VAR_PREFIXES.insert(0, 'TA')
10
-
11
- add_deprecation_to_ht_env()
12
4
  from traceableai.agent import Agent # pylint:disable=C0413
13
5
 
14
6
  from traceableai.config.config import Config # pylint:disable=C0413,C0412
15
- from hypertrace.agent.custom_logger import get_custom_logger # pylint:disable=C0413,C0412,C0411
7
+ from traceableai.custom_logger import get_custom_logger # pylint:disable=C0413,C0412,C0411
16
8
 
17
9
  config = Config()
18
10
  logger = get_custom_logger(__name__)
@@ -1,26 +1,27 @@
1
1
  import copy
2
2
  import json
3
- import logging
4
3
  import os
5
- from os import environ
6
4
 
7
5
  import yaml
8
6
 
9
7
  from google.protobuf import json_format
10
8
 
11
- from traceableai.config import traceable_config_pb2
9
+ from traceableai.config import config_pb2
12
10
  from traceableai.config.default import DEFAULT
13
11
  from traceableai.config.environment import overwrite_with_environment
14
- logger = logging.getLogger(__name__)
12
+ from traceableai.custom_logger import get_custom_logger
13
+ logger = get_custom_logger(__name__)
15
14
 
16
15
  REMOTE_CONFIG_KEY = 'remote_config'
17
16
  BLOCKING_CONFIG_KEY = 'blocking_config'
18
17
 
19
18
  class Config(): # pylint:disable=R0903
19
+ _instance = None
20
+
20
21
  def __new__(cls):
21
- if not hasattr(cls, 'instance'):
22
- cls.instance = super(Config, cls).__new__(cls)
23
- return cls.instance
22
+ if not hasattr(cls, "_instance") or cls._instance is None:
23
+ cls._instance = super(Config, cls).__new__(cls)
24
+ return cls._instance
24
25
 
25
26
  def __init__(self):
26
27
  if not hasattr(self, '_initialized'):
@@ -42,7 +43,7 @@ def merge_config(base_config, overriding_config):
42
43
  # 2.) Override the defaults with config file
43
44
  # 3.) Override the config file with env vars
44
45
  def build_config():
45
- traceable_config = traceable_config_pb2.AgentConfig()
46
+ traceable_config = config_pb2.AgentConfig()
46
47
  config_dict = copy.deepcopy(DEFAULT)
47
48
  file_dict = read_from_file()
48
49
  if file_dict is not None:
@@ -62,7 +63,7 @@ def read_from_file():
62
63
  logger.debug("TA_CONFIG_FILE path not set")
63
64
  return None
64
65
 
65
- with open(config_path, 'r') as config_file:
66
+ with open(config_path, 'r', encoding="UTF-8") as config_file:
66
67
  try:
67
68
  file_dict = yaml.safe_load(config_file)
68
69
  # setting the new remote config with deprecated one if the new one doesn't exist
@@ -77,7 +78,7 @@ def read_from_file():
77
78
  return None
78
79
 
79
80
  def _config_file_path():
80
- config_path = environ.get('TA_CONFIG_FILE', None)
81
+ config_path = os.environ.get('TA_CONFIG_FILE', None)
81
82
  if config_path is None:
82
83
  return None
83
84
  return config_path