odigos-opentelemetry-python 0.1.2__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.
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 1.2
2
+ Name: odigos-opentelemetry-python
3
+ Version: 0.1.2
4
+ Summary: Odigos Initializer for Python OpenTelemetry Components
5
+ Home-page: UNKNOWN
6
+ Author: Tamir David
7
+ Author-email: tamir@odigos.io
8
+ License: UNKNOWN
9
+ Description: UNKNOWN
10
+ Platform: UNKNOWN
11
+ Requires-Python: >=3.8
@@ -0,0 +1,7 @@
1
+ # @odigos/opentelemetry-python
2
+
3
+ Odigos initializer of OpenTelemetry for Python
4
+
5
+ This package is utilized in the Odigos project to initialize OpenTelemetry components for automatic instrumentation of Python applications.
6
+
7
+ Note: This package is currently meant to be used in the odigos project with odigos OpAMP server. It cannot be used as a standalone package in arbitrary Python applications.
@@ -0,0 +1,123 @@
1
+ import threading
2
+ import atexit
3
+ import sys
4
+ import os
5
+ import opentelemetry.sdk._configuration as sdk_config
6
+
7
+ from opentelemetry.sdk.resources import Resource
8
+ from opentelemetry.sdk.resources import ProcessResourceDetector, OTELResourceDetector
9
+ from opentelemetry.sdk.trace import TracerProvider
10
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
11
+ from opentelemetry.trace import set_tracer_provider
12
+
13
+ from .lib_handling import reorder_python_path, reload_distro_modules
14
+ from .version import VERSION
15
+
16
+ # from .odigos_sampler import OdigosSampler
17
+ # from opentelemetry.sdk.trace.sampling import ParentBased
18
+
19
+ from opamp.http_client import OpAMPHTTPClient
20
+
21
+
22
+ MINIMUM_PYTHON_SUPPORTED_VERSION = (3, 8)
23
+
24
+ def _initialize_components(trace_exporters = None, metric_exporters = None, log_exporters = None , span_processor = None):
25
+ resource_attributes_event = threading.Event()
26
+ client = None
27
+
28
+ try:
29
+
30
+ client = start_opamp_client(resource_attributes_event)
31
+ resource_attributes_event.wait(timeout=30) # Wait for the resource attributes to be received for 30 seconds
32
+
33
+ received_value = client.resource_attributes
34
+
35
+ if received_value:
36
+
37
+ auto_resource = {
38
+ "telemetry.distro.name": "odigos",
39
+ "telemetry.distro.version": VERSION,
40
+ }
41
+
42
+ auto_resource.update(received_value)
43
+
44
+ resource = Resource.create(auto_resource) \
45
+ .merge(OTELResourceDetector().detect()) \
46
+ .merge(ProcessResourceDetector().detect())
47
+
48
+ initialize_traces_if_enabled(trace_exporters, resource, span_processor)
49
+ initialize_metrics_if_enabled(metric_exporters, resource)
50
+ initialize_logging_if_enabled(log_exporters, resource)
51
+
52
+ # Reorder the python sys.path to ensure that the user application's dependencies take precedence over the agent's dependencies.
53
+ # This is necessary because the user application's dependencies may be incompatible with those used by the agent.
54
+ reorder_python_path()
55
+ # Reload distro modules to ensure the new path is used.
56
+ reload_distro_modules()
57
+
58
+ except Exception as e:
59
+ if client is not None:
60
+ client.shutdown(custom_failure_message=str(e))
61
+
62
+
63
+ def initialize_traces_if_enabled(trace_exporters, resource, span_processor = None):
64
+ traces_enabled = os.getenv(sdk_config.OTEL_TRACES_EXPORTER, "none").strip().lower()
65
+ if traces_enabled != "none":
66
+
67
+ provider = TracerProvider(resource=resource)
68
+
69
+ # TODO: uncomment once the OdigosSampler is implemented
70
+ # odigos_sampler = OdigosSampler()
71
+ # sampler = ParentBased(odigos_sampler)
72
+
73
+ # Exporting using exporters
74
+ if trace_exporters is not None:
75
+ id_generator_name = sdk_config._get_id_generator()
76
+ id_generator = sdk_config._import_id_generator(id_generator_name)
77
+ provider.id_generator = id_generator
78
+
79
+ set_tracer_provider(provider)
80
+
81
+ for _, exporter_class in trace_exporters.items():
82
+ exporter_args = {}
83
+ provider.add_span_processor(
84
+ BatchSpanProcessor(exporter_class(**exporter_args))
85
+ )
86
+
87
+ # Exporting using EBPF
88
+ else:
89
+ if span_processor is not None:
90
+ provider.add_span_processor(span_processor)
91
+
92
+ # return sampler
93
+
94
+ def initialize_metrics_if_enabled(metric_exporters, resource):
95
+ metrics_enabled = os.getenv(sdk_config.OTEL_METRICS_EXPORTER, "none").strip().lower()
96
+ if metrics_enabled != "none":
97
+ sdk_config._init_metrics(metric_exporters, resource)
98
+
99
+ def initialize_logging_if_enabled(log_exporters, resource):
100
+ logging_enabled = os.getenv(sdk_config.OTEL_LOGS_EXPORTER, "none").strip().lower()
101
+ if logging_enabled != "none":
102
+ sdk_config._init_logging(log_exporters, resource)
103
+
104
+
105
+ def start_opamp_client(event):
106
+ condition = threading.Condition(threading.Lock())
107
+ client = OpAMPHTTPClient(event, condition)
108
+
109
+ python_version_supported = is_supported_python_version()
110
+
111
+ client.start(python_version_supported)
112
+
113
+ def shutdown():
114
+ client.shutdown()
115
+
116
+ # Ensure that the shutdown function is called on program exit
117
+ atexit.register(shutdown)
118
+
119
+ return client
120
+
121
+
122
+ def is_supported_python_version():
123
+ return sys.version_info >= MINIMUM_PYTHON_SUPPORTED_VERSION
@@ -0,0 +1,34 @@
1
+ import sys
2
+
3
+ def reorder_python_path():
4
+ paths_to_move = [path for path in sys.path if path.startswith('/var/odigos/python')]
5
+
6
+ for path in paths_to_move:
7
+ sys.path.remove(path)
8
+ sys.path.append(path)
9
+
10
+
11
+ def reload_distro_modules() -> None:
12
+ # Delete distro modules and their sub-modules, as they have been imported before the path was reordered.
13
+ # The distro modules will be re-imported from the new path.
14
+ needed_module_prefixes = [
15
+ 'google.protobuf',
16
+ 'requests',
17
+ 'charset_normalizer',
18
+ 'certifi',
19
+ 'asgiref'
20
+ 'idna',
21
+ 'deprecated',
22
+ 'importlib_metadata',
23
+ 'packaging',
24
+ 'psutil',
25
+ 'zipp',
26
+ 'urllib3',
27
+ 'uuid_extensions.uuid7',
28
+ 'typing_extensions',
29
+ ]
30
+
31
+ for module in list(sys.modules):
32
+ # Check if the module starts with any of the needed prefixes
33
+ if any(module.startswith(prefix) for prefix in needed_module_prefixes):
34
+ del sys.modules[module]
@@ -0,0 +1,2 @@
1
+ # the content of the file is replaced with the real version in the odiglet DOCKERFILE
2
+ VERSION = "development"
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 1.2
2
+ Name: odigos-opentelemetry-python
3
+ Version: 0.1.2
4
+ Summary: Odigos Initializer for Python OpenTelemetry Components
5
+ Home-page: UNKNOWN
6
+ Author: Tamir David
7
+ Author-email: tamir@odigos.io
8
+ License: UNKNOWN
9
+ Description: UNKNOWN
10
+ Platform: UNKNOWN
11
+ Requires-Python: >=3.8
@@ -0,0 +1,17 @@
1
+ README.md
2
+ setup.py
3
+ initializer/__init__.py
4
+ initializer/components.py
5
+ initializer/lib_handling.py
6
+ initializer/version.py
7
+ odigos_opentelemetry_python.egg-info/PKG-INFO
8
+ odigos_opentelemetry_python.egg-info/SOURCES.txt
9
+ odigos_opentelemetry_python.egg-info/dependency_links.txt
10
+ odigos_opentelemetry_python.egg-info/requires.txt
11
+ odigos_opentelemetry_python.egg-info/top_level.txt
12
+ opamp/__init__.py
13
+ opamp/anyvalue_pb2.py
14
+ opamp/health_status.py
15
+ opamp/http_client.py
16
+ opamp/opamp_pb2.py
17
+ opamp/utils.py
@@ -0,0 +1,51 @@
1
+ requests~=2.7
2
+ protobuf<5.0,>=3.19
3
+ uuid7==0.1.0
4
+ opentelemetry-distro==0.45b0
5
+ opentelemetry-exporter-otlp-proto-http==1.24.0
6
+ opentelemetry-instrumentation==0.45b0
7
+ opentelemetry-instrumentation-aio-pika==0.45b0
8
+ opentelemetry-instrumentation-aiohttp-client==0.45b0
9
+ opentelemetry-instrumentation-aiopg==0.45b0
10
+ opentelemetry-instrumentation-asgi==0.45b0
11
+ opentelemetry-instrumentation-asyncio==0.45b0
12
+ opentelemetry-instrumentation-asyncpg==0.45b0
13
+ opentelemetry-instrumentation-boto==0.45b0
14
+ opentelemetry-instrumentation-boto3sqs==0.45b0
15
+ opentelemetry-instrumentation-botocore==0.45b0
16
+ opentelemetry-instrumentation-cassandra==0.45b0
17
+ opentelemetry-instrumentation-celery==0.45b0
18
+ opentelemetry-instrumentation-confluent-kafka==0.45b0
19
+ opentelemetry-instrumentation-dbapi==0.45b0
20
+ opentelemetry-instrumentation-django==0.45b0
21
+ opentelemetry-instrumentation-elasticsearch==0.45b0
22
+ opentelemetry-instrumentation-falcon==0.45b0
23
+ opentelemetry-instrumentation-fastapi==0.45b0
24
+ opentelemetry-instrumentation-flask==0.45b0
25
+ opentelemetry-instrumentation-grpc==0.45b0
26
+ opentelemetry-instrumentation-httpx==0.45b0
27
+ opentelemetry-instrumentation-jinja2==0.45b0
28
+ opentelemetry-instrumentation-kafka-python==0.45b0
29
+ opentelemetry-instrumentation-logging==0.45b0
30
+ opentelemetry-instrumentation-mysql==0.45b0
31
+ opentelemetry-instrumentation-mysqlclient==0.45b0
32
+ opentelemetry-instrumentation-pika==0.45b0
33
+ opentelemetry-instrumentation-psycopg==0.45b0
34
+ opentelemetry-instrumentation-psycopg2==0.45b0
35
+ opentelemetry-instrumentation-pymemcache==0.45b0
36
+ opentelemetry-instrumentation-pymongo==0.45b0
37
+ opentelemetry-instrumentation-pymysql==0.45b0
38
+ opentelemetry-instrumentation-pyramid==0.45b0
39
+ opentelemetry-instrumentation-redis==0.45b0
40
+ opentelemetry-instrumentation-remoulade==0.45b0
41
+ opentelemetry-instrumentation-requests==0.45b0
42
+ opentelemetry-instrumentation-sklearn==0.45b0
43
+ opentelemetry-instrumentation-sqlalchemy==0.45b0
44
+ opentelemetry-instrumentation-sqlite3==0.45b0
45
+ opentelemetry-instrumentation-starlette==0.45b0
46
+ opentelemetry-instrumentation-system-metrics==0.45b0
47
+ opentelemetry-instrumentation-tornado==0.45b0
48
+ opentelemetry-instrumentation-tortoiseorm==0.45b0
49
+ opentelemetry-instrumentation-urllib==0.45b0
50
+ opentelemetry-instrumentation-urllib3==0.45b0
51
+ opentelemetry-instrumentation-wsgi==0.45b0
File without changes
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: anyvalue.proto
4
+ # Protobuf Python Version: 4.25.0
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+
16
+
17
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0e\x61nyvalue.proto\x12\x0bopamp.proto\"\xbc\x02\n\x08\x41nyValue\x12#\n\x0cstring_value\x18\x01 \x01(\tH\x00R\x0bstringValue\x12\x1f\n\nbool_value\x18\x02 \x01(\x08H\x00R\tboolValue\x12\x1d\n\tint_value\x18\x03 \x01(\x03H\x00R\x08intValue\x12#\n\x0c\x64ouble_value\x18\x04 \x01(\x01H\x00R\x0b\x64oubleValue\x12:\n\x0b\x61rray_value\x18\x05 \x01(\x0b\x32\x17.opamp.proto.ArrayValueH\x00R\narrayValue\x12>\n\x0ckvlist_value\x18\x06 \x01(\x0b\x32\x19.opamp.proto.KeyValueListH\x00R\x0bkvlistValue\x12!\n\x0b\x62ytes_value\x18\x07 \x01(\x0cH\x00R\nbytesValueB\x07\n\x05value\";\n\nArrayValue\x12-\n\x06values\x18\x01 \x03(\x0b\x32\x15.opamp.proto.AnyValueR\x06values\"=\n\x0cKeyValueList\x12-\n\x06values\x18\x01 \x03(\x0b\x32\x15.opamp.proto.KeyValueR\x06values\"I\n\x08KeyValue\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12+\n\x05value\x18\x02 \x01(\x0b\x32\x15.opamp.proto.AnyValueR\x05valueB\xa0\x01\n\x0f\x63om.opamp.protoB\rAnyvalueProtoP\x01Z1github.com/odigos-io/odigos/opampserver/protobufs\xa2\x02\x03OPX\xaa\x02\x0bOpamp.Proto\xca\x02\x0bOpamp\\Proto\xe2\x02\x17Opamp\\Proto\\GPBMetadata\xea\x02\x0cOpamp::Protob\x06proto3')
18
+
19
+ _globals = globals()
20
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
21
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'anyvalue_pb2', _globals)
22
+ if _descriptor._USE_C_DESCRIPTORS == False:
23
+ _globals['DESCRIPTOR']._options = None
24
+ _globals['DESCRIPTOR']._serialized_options = b'\n\017com.opamp.protoB\rAnyvalueProtoP\001Z1github.com/odigos-io/odigos/opampserver/protobufs\242\002\003OPX\252\002\013Opamp.Proto\312\002\013Opamp\\Proto\342\002\027Opamp\\Proto\\GPBMetadata\352\002\014Opamp::Proto'
25
+ _globals['_ANYVALUE']._serialized_start=32
26
+ _globals['_ANYVALUE']._serialized_end=348
27
+ _globals['_ARRAYVALUE']._serialized_start=350
28
+ _globals['_ARRAYVALUE']._serialized_end=409
29
+ _globals['_KEYVALUELIST']._serialized_start=411
30
+ _globals['_KEYVALUELIST']._serialized_end=472
31
+ _globals['_KEYVALUE']._serialized_start=474
32
+ _globals['_KEYVALUE']._serialized_end=547
33
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,8 @@
1
+ from enum import Enum
2
+
3
+ class AgentHealthStatus(str, Enum):
4
+ HEALTHY = "Healthy"
5
+ STARTING = "Starting"
6
+ UNSUPPORTED_RUNTIME_VERSION = "UnsupportedRuntimeVersion"
7
+ TERMINATED = "ProcessTerminated"
8
+ AGENT_FAILURE = "AgentFailure"
@@ -0,0 +1,265 @@
1
+ import os
2
+ import sys
3
+ import time
4
+ import threading
5
+ import requests
6
+ import logging
7
+
8
+ from uuid_extensions import uuid7
9
+ from opentelemetry.semconv.resource import ResourceAttributes
10
+ from opentelemetry.context import (
11
+ _SUPPRESS_HTTP_INSTRUMENTATION_KEY,
12
+ attach,
13
+ detach,
14
+ set_value,
15
+ )
16
+
17
+ from opamp import opamp_pb2, anyvalue_pb2, utils
18
+ from opamp.health_status import AgentHealthStatus
19
+
20
+ # Setup the logger
21
+ opamp_logger = logging.getLogger(__name__)
22
+ opamp_logger.setLevel(logging.DEBUG)
23
+ opamp_logger.disabled = True # Comment this line to enable the logger
24
+
25
+
26
+ class OpAMPHTTPClient:
27
+ def __init__(self, event, condition: threading.Condition):
28
+ self.server_host = os.getenv('ODIGOS_OPAMP_SERVER_HOST')
29
+ self.instrumentation_device_id = os.getenv('ODIGOS_INSTRUMENTATION_DEVICE_ID')
30
+ self.server_url = f"http://{self.server_host}/v1/opamp"
31
+ self.resource_attributes = {}
32
+ self.running = True
33
+ self.condition = condition
34
+ self.event = event
35
+ self.next_sequence_num = 0
36
+ self.instance_uid = uuid7().__str__()
37
+ self.remote_config_status = None
38
+
39
+
40
+ def start(self, python_version_supported: bool = None):
41
+ if not python_version_supported:
42
+
43
+ python_version = f'{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}'
44
+ error_message = f"Opentelemetry SDK require Python in version 3.8 or higher [{python_version} is not supported]"
45
+
46
+ opamp_logger.warning(f"{error_message}, sending disconnect message to OpAMP server...")
47
+ self.send_unsupported_version_disconnect_message(error_message=error_message)
48
+ self.event.set()
49
+ return
50
+
51
+ self.client_thread = threading.Thread(target=self.run, name="OpAMPClientThread", daemon=True)
52
+ self.client_thread.start()
53
+
54
+ def run(self):
55
+ try:
56
+ if not self.mandatory_env_vars_set():
57
+ self.event.set()
58
+ return
59
+
60
+ self.send_first_message_with_retry()
61
+ self.event.set()
62
+
63
+ self.worker()
64
+
65
+ except Exception as e:
66
+ opamp_logger.error(f"Error running OpAMP client: {e}")
67
+ failure_message = self.get_agent_failure_disconnect_message(error_message=str(e))
68
+ self.send_agent_to_server_message(failure_message)
69
+
70
+ # Exiting the opamp thread and set the event to notify the main thread
71
+ self.event.set()
72
+ sys.exit()
73
+
74
+ def get_agent_failure_disconnect_message(self, error_message: str) -> None:
75
+ agent_failure_message = opamp_pb2.AgentToServer()
76
+
77
+ agent_disconnect = self.get_agent_disconnect()
78
+ agent_failure_message.agent_disconnect.CopyFrom(agent_disconnect)
79
+
80
+ agent_health = self.get_agent_health(component_health=False, last_error=error_message, status=AgentHealthStatus.AGENT_FAILURE.value)
81
+ agent_failure_message.health.CopyFrom(agent_health)
82
+
83
+ return agent_failure_message
84
+
85
+ def send_unsupported_version_disconnect_message(self, error_message: str) -> None:
86
+ first_disconnect_message = opamp_pb2.AgentToServer()
87
+
88
+ agent_description = self.get_agent_description()
89
+
90
+ first_disconnect_message.agent_description.CopyFrom(agent_description)
91
+
92
+ agent_disconnect = self.get_agent_disconnect()
93
+ first_disconnect_message.agent_disconnect.CopyFrom(agent_disconnect)
94
+
95
+ agent_health = self.get_agent_health(component_health=False, last_error=error_message, status=AgentHealthStatus.UNSUPPORTED_RUNTIME_VERSION.value)
96
+ first_disconnect_message.health.CopyFrom(agent_health)
97
+
98
+ self.send_agent_to_server_message(first_disconnect_message)
99
+
100
+ def send_first_message_with_retry(self) -> None:
101
+ max_retries = 5
102
+ delay = 2
103
+ for attempt in range(1, max_retries + 1):
104
+ try:
105
+ # Send first message to OpAMP server, Health is false as the component is not initialized
106
+ agent_health = self.get_agent_health(component_health=False, last_error="Python OpenTelemetry agent is starting", status=AgentHealthStatus.STARTING.value)
107
+ agent_description = self.get_agent_description()
108
+ first_message_server_to_agent = self.send_agent_to_server_message(opamp_pb2.AgentToServer(agent_description=agent_description, health=agent_health))
109
+
110
+ self.update_remote_config_status(first_message_server_to_agent)
111
+ self.resource_attributes = utils.parse_first_message_to_resource_attributes(first_message_server_to_agent, opamp_logger)
112
+
113
+ # Send healthy message to OpAMP server
114
+ opamp_logger.info("Reporting healthy to OpAMP server...")
115
+ agent_health = self.get_agent_health(component_health=True, status=AgentHealthStatus.HEALTHY.value)
116
+ self.send_agent_to_server_message(opamp_pb2.AgentToServer(health=agent_health))
117
+
118
+ break
119
+ except Exception as e:
120
+ opamp_logger.error(f"Error sending full state to OpAMP server: {e}")
121
+
122
+ if attempt < max_retries:
123
+ time.sleep(delay)
124
+
125
+ def worker(self):
126
+ while self.running:
127
+ with self.condition:
128
+ try:
129
+ server_to_agent = self.send_heartbeat()
130
+ if self.update_remote_config_status(server_to_agent):
131
+ opamp_logger.info("Remote config updated, applying changes...")
132
+ # TODO: implement changes based on the remote config
133
+
134
+ if server_to_agent.flags & opamp_pb2.ServerToAgentFlags_ReportFullState:
135
+ opamp_logger.info("Received request to report full state")
136
+
137
+ agent_description = self.get_agent_description()
138
+ agent_health = self.get_agent_health(component_health=True, status=AgentHealthStatus.HEALTHY.value)
139
+ agent_to_server = opamp_pb2.AgentToServer(agent_description=agent_description, health=agent_health)
140
+
141
+ server_to_agent = self.send_agent_to_server_message(agent_to_server)
142
+
143
+ self.update_remote_config_status(server_to_agent)
144
+
145
+ except requests.RequestException as e:
146
+ opamp_logger.error(f"Error fetching data: {e}")
147
+ self.condition.wait(30)
148
+
149
+ def send_heartbeat(self) -> opamp_pb2.ServerToAgent:
150
+ opamp_logger.debug("Sending heartbeat to OpAMP server...")
151
+ try:
152
+ agent_to_server = opamp_pb2.AgentToServer(remote_config_status=self.remote_config_status)
153
+ return self.send_agent_to_server_message(agent_to_server)
154
+ except requests.RequestException as e:
155
+ opamp_logger.error(f"Error sending heartbeat to OpAMP server: {e}")
156
+
157
+ def get_agent_description(self) -> opamp_pb2.AgentDescription:
158
+ identifying_attributes = [
159
+ anyvalue_pb2.KeyValue(
160
+ key=ResourceAttributes.SERVICE_INSTANCE_ID,
161
+ value=anyvalue_pb2.AnyValue(string_value=self.instance_uid)
162
+ ),
163
+ anyvalue_pb2.KeyValue(
164
+ key=ResourceAttributes.PROCESS_PID,
165
+ value=anyvalue_pb2.AnyValue(int_value=os.getpid())
166
+ ),
167
+ anyvalue_pb2.KeyValue(
168
+ key=ResourceAttributes.TELEMETRY_SDK_LANGUAGE,
169
+ value=anyvalue_pb2.AnyValue(string_value="python")
170
+ )
171
+ ]
172
+
173
+ return opamp_pb2.AgentDescription(
174
+ identifying_attributes=identifying_attributes,
175
+ non_identifying_attributes=[]
176
+ )
177
+
178
+ def get_agent_disconnect(self) -> opamp_pb2.AgentDisconnect:
179
+ return opamp_pb2.AgentDisconnect()
180
+
181
+ def get_agent_health(self, component_health: bool = None, last_error : str = None, status: str = None) -> opamp_pb2.ComponentHealth:
182
+ health = opamp_pb2.ComponentHealth(
183
+ )
184
+ if component_health is not None:
185
+ health.healthy = component_health
186
+ if last_error is not None:
187
+ health.last_error = last_error
188
+ if status is not None:
189
+ health.status = status
190
+
191
+ return health
192
+
193
+
194
+ def send_agent_to_server_message(self, message: opamp_pb2.AgentToServer) -> opamp_pb2.ServerToAgent:
195
+
196
+ message.instance_uid = self.instance_uid.encode('utf-8')
197
+ message.sequence_num = self.next_sequence_num
198
+ if self.remote_config_status:
199
+ message.remote_config_status.CopyFrom(self.remote_config_status)
200
+
201
+ self.next_sequence_num += 1
202
+ message_bytes = message.SerializeToString()
203
+
204
+ headers = {
205
+ "Content-Type": "application/x-protobuf",
206
+ "X-Odigos-DeviceId": self.instrumentation_device_id
207
+ }
208
+
209
+ try:
210
+ agent_message = attach(set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True))
211
+ response = requests.post(self.server_url, data=message_bytes, headers=headers, timeout=5)
212
+ response.raise_for_status()
213
+ except requests.Timeout:
214
+ opamp_logger.error("Timeout sending message to OpAMP server")
215
+ return opamp_pb2.ServerToAgent()
216
+ except requests.ConnectionError as e:
217
+ opamp_logger.error(f"Error sending message to OpAMP server: {e}")
218
+ return opamp_pb2.ServerToAgent()
219
+ finally:
220
+ detach(agent_message)
221
+
222
+ server_to_agent = opamp_pb2.ServerToAgent()
223
+ try:
224
+ server_to_agent.ParseFromString(response.content)
225
+ except NotImplementedError as e:
226
+ opamp_logger.error(f"Error parsing response from OpAMP server: {e}")
227
+ return opamp_pb2.ServerToAgent()
228
+ return server_to_agent
229
+
230
+ def mandatory_env_vars_set(self):
231
+ mandatory_env_vars = {
232
+ "ODIGOS_OPAMP_SERVER_HOST": self.server_host,
233
+ "ODIGOS_INSTRUMENTATION_DEVICE_ID": self.instrumentation_device_id
234
+ }
235
+
236
+ for env_var, value in mandatory_env_vars.items():
237
+ if not value:
238
+ opamp_logger.error(f"{env_var} environment variable not set")
239
+ return False
240
+
241
+ return True
242
+
243
+ def shutdown(self, custom_failure_message: str = None):
244
+ self.running = False
245
+ opamp_logger.info("Sending agent disconnect message to OpAMP server...")
246
+ if custom_failure_message:
247
+ disconnect_message = self.get_agent_failure_disconnect_message(error_message=custom_failure_message)
248
+ else:
249
+ agent_health = self.get_agent_health(component_health=False, last_error="Python runtime is exiting", status=AgentHealthStatus.TERMINATED.value)
250
+ disconnect_message = opamp_pb2.AgentToServer(agent_disconnect=opamp_pb2.AgentDisconnect(), health=agent_health)
251
+
252
+ with self.condition:
253
+ self.condition.notify_all()
254
+ self.client_thread.join()
255
+
256
+ self.send_agent_to_server_message(disconnect_message)
257
+
258
+ def update_remote_config_status(self, server_to_agent: opamp_pb2.ServerToAgent) -> bool:
259
+ if server_to_agent.HasField("remote_config"):
260
+ remote_config_hash = server_to_agent.remote_config.config_hash
261
+ remote_config_status = opamp_pb2.RemoteConfigStatus(last_remote_config_hash=remote_config_hash)
262
+ self.remote_config_status = remote_config_status
263
+ return True
264
+
265
+ return False
@@ -0,0 +1,129 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: opamp.proto
4
+ # Protobuf Python Version: 4.25.0
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+ from opamp import anyvalue_pb2
15
+
16
+
17
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0bopamp.proto\x12\x0bopamp.proto\x1a\x0e\x61nyvalue.proto\"\xbc\x06\n\rAgentToServer\x12!\n\x0cinstance_uid\x18\x01 \x01(\x0cR\x0binstanceUid\x12!\n\x0csequence_num\x18\x02 \x01(\x04R\x0bsequenceNum\x12J\n\x11\x61gent_description\x18\x03 \x01(\x0b\x32\x1d.opamp.proto.AgentDescriptionR\x10\x61gentDescription\x12\"\n\x0c\x63\x61pabilities\x18\x04 \x01(\x04R\x0c\x63\x61pabilities\x12\x34\n\x06health\x18\x05 \x01(\x0b\x32\x1c.opamp.proto.ComponentHealthR\x06health\x12G\n\x10\x65\x66\x66\x65\x63tive_config\x18\x06 \x01(\x0b\x32\x1c.opamp.proto.EffectiveConfigR\x0f\x65\x66\x66\x65\x63tiveConfig\x12Q\n\x14remote_config_status\x18\x07 \x01(\x0b\x32\x1f.opamp.proto.RemoteConfigStatusR\x12remoteConfigStatus\x12G\n\x10package_statuses\x18\x08 \x01(\x0b\x32\x1c.opamp.proto.PackageStatusesR\x0fpackageStatuses\x12G\n\x10\x61gent_disconnect\x18\t \x01(\x0b\x32\x1c.opamp.proto.AgentDisconnectR\x0f\x61gentDisconnect\x12\x14\n\x05\x66lags\x18\n \x01(\x04R\x05\x66lags\x12\x66\n\x1b\x63onnection_settings_request\x18\x0b \x01(\x0b\x32&.opamp.proto.ConnectionSettingsRequestR\x19\x63onnectionSettingsRequest\x12P\n\x13\x63ustom_capabilities\x18\x0c \x01(\x0b\x32\x1f.opamp.proto.CustomCapabilitiesR\x12\x63ustomCapabilities\x12\x41\n\x0e\x63ustom_message\x18\r \x01(\x0b\x32\x1a.opamp.proto.CustomMessageR\rcustomMessage\"\x11\n\x0f\x41gentDisconnect\"^\n\x19\x43onnectionSettingsRequest\x12\x41\n\x05opamp\x18\x01 \x01(\x0b\x32+.opamp.proto.OpAMPConnectionSettingsRequestR\x05opamp\"r\n\x1eOpAMPConnectionSettingsRequest\x12P\n\x13\x63\x65rtificate_request\x18\x01 \x01(\x0b\x32\x1f.opamp.proto.CertificateRequestR\x12\x63\x65rtificateRequest\"&\n\x12\x43\x65rtificateRequest\x12\x10\n\x03\x63sr\x18\x01 \x01(\x0cR\x03\x63sr\"\xc8\x05\n\rServerToAgent\x12!\n\x0cinstance_uid\x18\x01 \x01(\x0cR\x0binstanceUid\x12G\n\x0e\x65rror_response\x18\x02 \x01(\x0b\x32 .opamp.proto.ServerErrorResponseR\rerrorResponse\x12\x43\n\rremote_config\x18\x03 \x01(\x0b\x32\x1e.opamp.proto.AgentRemoteConfigR\x0cremoteConfig\x12V\n\x13\x63onnection_settings\x18\x04 \x01(\x0b\x32%.opamp.proto.ConnectionSettingsOffersR\x12\x63onnectionSettings\x12M\n\x12packages_available\x18\x05 \x01(\x0b\x32\x1e.opamp.proto.PackagesAvailableR\x11packagesAvailable\x12\x14\n\x05\x66lags\x18\x06 \x01(\x04R\x05\x66lags\x12\"\n\x0c\x63\x61pabilities\x18\x07 \x01(\x04R\x0c\x63\x61pabilities\x12S\n\x14\x61gent_identification\x18\x08 \x01(\x0b\x32 .opamp.proto.AgentIdentificationR\x13\x61gentIdentification\x12;\n\x07\x63ommand\x18\t \x01(\x0b\x32!.opamp.proto.ServerToAgentCommandR\x07\x63ommand\x12P\n\x13\x63ustom_capabilities\x18\n \x01(\x0b\x32\x1f.opamp.proto.CustomCapabilitiesR\x12\x63ustomCapabilities\x12\x41\n\x0e\x63ustom_message\x18\x0b \x01(\x0b\x32\x1a.opamp.proto.CustomMessageR\rcustomMessage\"\xbb\x01\n\x17OpAMPConnectionSettings\x12\x31\n\x14\x64\x65stination_endpoint\x18\x01 \x01(\tR\x13\x64\x65stinationEndpoint\x12.\n\x07headers\x18\x02 \x01(\x0b\x32\x14.opamp.proto.HeadersR\x07headers\x12=\n\x0b\x63\x65rtificate\x18\x03 \x01(\x0b\x32\x1b.opamp.proto.TLSCertificateR\x0b\x63\x65rtificate\"\xbf\x01\n\x1bTelemetryConnectionSettings\x12\x31\n\x14\x64\x65stination_endpoint\x18\x01 \x01(\tR\x13\x64\x65stinationEndpoint\x12.\n\x07headers\x18\x02 \x01(\x0b\x32\x14.opamp.proto.HeadersR\x07headers\x12=\n\x0b\x63\x65rtificate\x18\x03 \x01(\x0b\x32\x1b.opamp.proto.TLSCertificateR\x0b\x63\x65rtificate\"\xdd\x02\n\x17OtherConnectionSettings\x12\x31\n\x14\x64\x65stination_endpoint\x18\x01 \x01(\tR\x13\x64\x65stinationEndpoint\x12.\n\x07headers\x18\x02 \x01(\x0b\x32\x14.opamp.proto.HeadersR\x07headers\x12=\n\x0b\x63\x65rtificate\x18\x03 \x01(\x0b\x32\x1b.opamp.proto.TLSCertificateR\x0b\x63\x65rtificate\x12^\n\x0eother_settings\x18\x04 \x03(\x0b\x32\x37.opamp.proto.OtherConnectionSettings.OtherSettingsEntryR\rotherSettings\x1a@\n\x12OtherSettingsEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n\x05value\x18\x02 \x01(\tR\x05value:\x02\x38\x01\"8\n\x07Headers\x12-\n\x07headers\x18\x01 \x03(\x0b\x32\x13.opamp.proto.HeaderR\x07headers\"0\n\x06Header\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n\x05value\x18\x02 \x01(\tR\x05value\"t\n\x0eTLSCertificate\x12\x1d\n\npublic_key\x18\x01 \x01(\x0cR\tpublicKey\x12\x1f\n\x0bprivate_key\x18\x02 \x01(\x0cR\nprivateKey\x12\"\n\rca_public_key\x18\x03 \x01(\x0cR\x0b\x63\x61PublicKey\"\x98\x04\n\x18\x43onnectionSettingsOffers\x12\x12\n\x04hash\x18\x01 \x01(\x0cR\x04hash\x12:\n\x05opamp\x18\x02 \x01(\x0b\x32$.opamp.proto.OpAMPConnectionSettingsR\x05opamp\x12I\n\x0bown_metrics\x18\x03 \x01(\x0b\x32(.opamp.proto.TelemetryConnectionSettingsR\nownMetrics\x12G\n\nown_traces\x18\x04 \x01(\x0b\x32(.opamp.proto.TelemetryConnectionSettingsR\townTraces\x12\x43\n\x08own_logs\x18\x05 \x01(\x0b\x32(.opamp.proto.TelemetryConnectionSettingsR\x07ownLogs\x12h\n\x11other_connections\x18\x06 \x03(\x0b\x32;.opamp.proto.ConnectionSettingsOffers.OtherConnectionsEntryR\x10otherConnections\x1ai\n\x15OtherConnectionsEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12:\n\x05value\x18\x02 \x01(\x0b\x32$.opamp.proto.OtherConnectionSettingsR\x05value:\x02\x38\x01\"\xe5\x01\n\x11PackagesAvailable\x12H\n\x08packages\x18\x01 \x03(\x0b\x32,.opamp.proto.PackagesAvailable.PackagesEntryR\x08packages\x12*\n\x11\x61ll_packages_hash\x18\x02 \x01(\x0cR\x0f\x61llPackagesHash\x1aZ\n\rPackagesEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x33\n\x05value\x18\x02 \x01(\x0b\x32\x1d.opamp.proto.PackageAvailableR\x05value:\x02\x38\x01\"\xa1\x01\n\x10PackageAvailable\x12,\n\x04type\x18\x01 \x01(\x0e\x32\x18.opamp.proto.PackageTypeR\x04type\x12\x18\n\x07version\x18\x02 \x01(\tR\x07version\x12\x31\n\x04\x66ile\x18\x03 \x01(\x0b\x32\x1d.opamp.proto.DownloadableFileR\x04\x66ile\x12\x12\n\x04hash\x18\x04 \x01(\x0cR\x04hash\"v\n\x10\x44ownloadableFile\x12!\n\x0c\x64ownload_url\x18\x01 \x01(\tR\x0b\x64ownloadUrl\x12!\n\x0c\x63ontent_hash\x18\x02 \x01(\x0cR\x0b\x63ontentHash\x12\x1c\n\tsignature\x18\x03 \x01(\x0cR\tsignature\"\xb8\x01\n\x13ServerErrorResponse\x12\x38\n\x04type\x18\x01 \x01(\x0e\x32$.opamp.proto.ServerErrorResponseTypeR\x04type\x12#\n\rerror_message\x18\x02 \x01(\tR\x0c\x65rrorMessage\x12\x37\n\nretry_info\x18\x03 \x01(\x0b\x32\x16.opamp.proto.RetryInfoH\x00R\tretryInfoB\t\n\x07\x44\x65tails\"C\n\tRetryInfo\x12\x36\n\x17retry_after_nanoseconds\x18\x01 \x01(\x04R\x15retryAfterNanoseconds\"D\n\x14ServerToAgentCommand\x12,\n\x04type\x18\x01 \x01(\x0e\x32\x18.opamp.proto.CommandTypeR\x04type\"\xb5\x01\n\x10\x41gentDescription\x12L\n\x16identifying_attributes\x18\x01 \x03(\x0b\x32\x15.opamp.proto.KeyValueR\x15identifyingAttributes\x12S\n\x1anon_identifying_attributes\x18\x02 \x03(\x0b\x32\x15.opamp.proto.KeyValueR\x18nonIdentifyingAttributes\"\x93\x03\n\x0f\x43omponentHealth\x12\x18\n\x07healthy\x18\x01 \x01(\x08R\x07healthy\x12/\n\x14start_time_unix_nano\x18\x02 \x01(\x06R\x11startTimeUnixNano\x12\x1d\n\nlast_error\x18\x03 \x01(\tR\tlastError\x12\x16\n\x06status\x18\x04 \x01(\tR\x06status\x12\x31\n\x15status_time_unix_nano\x18\x05 \x01(\x06R\x12statusTimeUnixNano\x12\x66\n\x14\x63omponent_health_map\x18\x06 \x03(\x0b\x32\x34.opamp.proto.ComponentHealth.ComponentHealthMapEntryR\x12\x63omponentHealthMap\x1a\x63\n\x17\x43omponentHealthMapEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32\x1c.opamp.proto.ComponentHealthR\x05value:\x02\x38\x01\"M\n\x0f\x45\x66\x66\x65\x63tiveConfig\x12:\n\nconfig_map\x18\x01 \x01(\x0b\x32\x1b.opamp.proto.AgentConfigMapR\tconfigMap\"\xab\x01\n\x12RemoteConfigStatus\x12\x35\n\x17last_remote_config_hash\x18\x01 \x01(\x0cR\x14lastRemoteConfigHash\x12\x39\n\x06status\x18\x02 \x01(\x0e\x32!.opamp.proto.RemoteConfigStatusesR\x06status\x12#\n\rerror_message\x18\x03 \x01(\tR\x0c\x65rrorMessage\"\xa1\x02\n\x0fPackageStatuses\x12\x46\n\x08packages\x18\x01 \x03(\x0b\x32*.opamp.proto.PackageStatuses.PackagesEntryR\x08packages\x12H\n!server_provided_all_packages_hash\x18\x02 \x01(\x0cR\x1dserverProvidedAllPackagesHash\x12#\n\rerror_message\x18\x03 \x01(\tR\x0c\x65rrorMessage\x1aW\n\rPackagesEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x30\n\x05value\x18\x02 \x01(\x0b\x32\x1a.opamp.proto.PackageStatusR\x05value:\x02\x38\x01\"\xb8\x02\n\rPackageStatus\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12*\n\x11\x61gent_has_version\x18\x02 \x01(\tR\x0f\x61gentHasVersion\x12$\n\x0e\x61gent_has_hash\x18\x03 \x01(\x0cR\x0c\x61gentHasHash\x12\x34\n\x16server_offered_version\x18\x04 \x01(\tR\x14serverOfferedVersion\x12.\n\x13server_offered_hash\x18\x05 \x01(\x0cR\x11serverOfferedHash\x12\x36\n\x06status\x18\x06 \x01(\x0e\x32\x1e.opamp.proto.PackageStatusEnumR\x06status\x12#\n\rerror_message\x18\x07 \x01(\tR\x0c\x65rrorMessage\"?\n\x13\x41gentIdentification\x12(\n\x10new_instance_uid\x18\x01 \x01(\x0cR\x0enewInstanceUid\"i\n\x11\x41gentRemoteConfig\x12\x33\n\x06\x63onfig\x18\x01 \x01(\x0b\x32\x1b.opamp.proto.AgentConfigMapR\x06\x63onfig\x12\x1f\n\x0b\x63onfig_hash\x18\x02 \x01(\x0cR\nconfigHash\"\xb7\x01\n\x0e\x41gentConfigMap\x12I\n\nconfig_map\x18\x01 \x03(\x0b\x32*.opamp.proto.AgentConfigMap.ConfigMapEntryR\tconfigMap\x1aZ\n\x0e\x43onfigMapEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32\x1c.opamp.proto.AgentConfigFileR\x05value:\x02\x38\x01\"H\n\x0f\x41gentConfigFile\x12\x12\n\x04\x62ody\x18\x01 \x01(\x0cR\x04\x62ody\x12!\n\x0c\x63ontent_type\x18\x02 \x01(\tR\x0b\x63ontentType\"8\n\x12\x43ustomCapabilities\x12\"\n\x0c\x63\x61pabilities\x18\x01 \x03(\tR\x0c\x63\x61pabilities\"W\n\rCustomMessage\x12\x1e\n\ncapability\x18\x01 \x01(\tR\ncapability\x12\x12\n\x04type\x18\x02 \x01(\tR\x04type\x12\x12\n\x04\x64\x61ta\x18\x03 \x01(\x0cR\x04\x64\x61ta*c\n\x12\x41gentToServerFlags\x12\"\n\x1e\x41gentToServerFlags_Unspecified\x10\x00\x12)\n%AgentToServerFlags_RequestInstanceUid\x10\x01*`\n\x12ServerToAgentFlags\x12\"\n\x1eServerToAgentFlags_Unspecified\x10\x00\x12&\n\"ServerToAgentFlags_ReportFullState\x10\x01*\xf7\x02\n\x12ServerCapabilities\x12\"\n\x1eServerCapabilities_Unspecified\x10\x00\x12$\n ServerCapabilities_AcceptsStatus\x10\x01\x12)\n%ServerCapabilities_OffersRemoteConfig\x10\x02\x12-\n)ServerCapabilities_AcceptsEffectiveConfig\x10\x04\x12%\n!ServerCapabilities_OffersPackages\x10\x08\x12,\n(ServerCapabilities_AcceptsPackagesStatus\x10\x10\x12/\n+ServerCapabilities_OffersConnectionSettings\x10 \x12\x37\n3ServerCapabilities_AcceptsConnectionSettingsRequest\x10@*>\n\x0bPackageType\x12\x18\n\x14PackageType_TopLevel\x10\x00\x12\x15\n\x11PackageType_Addon\x10\x01*\x8f\x01\n\x17ServerErrorResponseType\x12#\n\x1fServerErrorResponseType_Unknown\x10\x00\x12&\n\"ServerErrorResponseType_BadRequest\x10\x01\x12\'\n#ServerErrorResponseType_Unavailable\x10\x02*&\n\x0b\x43ommandType\x12\x17\n\x13\x43ommandType_Restart\x10\x00*\xef\x04\n\x11\x41gentCapabilities\x12!\n\x1d\x41gentCapabilities_Unspecified\x10\x00\x12#\n\x1f\x41gentCapabilities_ReportsStatus\x10\x01\x12)\n%AgentCapabilities_AcceptsRemoteConfig\x10\x02\x12,\n(AgentCapabilities_ReportsEffectiveConfig\x10\x04\x12%\n!AgentCapabilities_AcceptsPackages\x10\x08\x12,\n(AgentCapabilities_ReportsPackageStatuses\x10\x10\x12&\n\"AgentCapabilities_ReportsOwnTraces\x10 \x12\'\n#AgentCapabilities_ReportsOwnMetrics\x10@\x12%\n AgentCapabilities_ReportsOwnLogs\x10\x80\x01\x12\x35\n0AgentCapabilities_AcceptsOpAMPConnectionSettings\x10\x80\x02\x12\x35\n0AgentCapabilities_AcceptsOtherConnectionSettings\x10\x80\x04\x12,\n\'AgentCapabilities_AcceptsRestartCommand\x10\x80\x08\x12$\n\x1f\x41gentCapabilities_ReportsHealth\x10\x80\x10\x12*\n%AgentCapabilities_ReportsRemoteConfig\x10\x80 *\x9c\x01\n\x14RemoteConfigStatuses\x12\x1e\n\x1aRemoteConfigStatuses_UNSET\x10\x00\x12 \n\x1cRemoteConfigStatuses_APPLIED\x10\x01\x12!\n\x1dRemoteConfigStatuses_APPLYING\x10\x02\x12\x1f\n\x1bRemoteConfigStatuses_FAILED\x10\x03*\xa1\x01\n\x11PackageStatusEnum\x12\x1f\n\x1bPackageStatusEnum_Installed\x10\x00\x12$\n PackageStatusEnum_InstallPending\x10\x01\x12 \n\x1cPackageStatusEnum_Installing\x10\x02\x12#\n\x1fPackageStatusEnum_InstallFailed\x10\x03\x42\x9d\x01\n\x0f\x63om.opamp.protoB\nOpampProtoP\x01Z1github.com/odigos-io/odigos/opampserver/protobufs\xa2\x02\x03OPX\xaa\x02\x0bOpamp.Proto\xca\x02\x0bOpamp\\Proto\xe2\x02\x17Opamp\\Proto\\GPBMetadata\xea\x02\x0cOpamp::Protob\x06proto3')
18
+
19
+ _globals = globals()
20
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
21
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'opamp_pb2', _globals)
22
+ if _descriptor._USE_C_DESCRIPTORS == False:
23
+ _globals['DESCRIPTOR']._options = None
24
+ _globals['DESCRIPTOR']._serialized_options = b'\n\017com.opamp.protoB\nOpampProtoP\001Z1github.com/odigos-io/odigos/opampserver/protobufs\242\002\003OPX\252\002\013Opamp.Proto\312\002\013Opamp\\Proto\342\002\027Opamp\\Proto\\GPBMetadata\352\002\014Opamp::Proto'
25
+ _globals['_OTHERCONNECTIONSETTINGS_OTHERSETTINGSENTRY']._options = None
26
+ _globals['_OTHERCONNECTIONSETTINGS_OTHERSETTINGSENTRY']._serialized_options = b'8\001'
27
+ _globals['_CONNECTIONSETTINGSOFFERS_OTHERCONNECTIONSENTRY']._options = None
28
+ _globals['_CONNECTIONSETTINGSOFFERS_OTHERCONNECTIONSENTRY']._serialized_options = b'8\001'
29
+ _globals['_PACKAGESAVAILABLE_PACKAGESENTRY']._options = None
30
+ _globals['_PACKAGESAVAILABLE_PACKAGESENTRY']._serialized_options = b'8\001'
31
+ _globals['_COMPONENTHEALTH_COMPONENTHEALTHMAPENTRY']._options = None
32
+ _globals['_COMPONENTHEALTH_COMPONENTHEALTHMAPENTRY']._serialized_options = b'8\001'
33
+ _globals['_PACKAGESTATUSES_PACKAGESENTRY']._options = None
34
+ _globals['_PACKAGESTATUSES_PACKAGESENTRY']._serialized_options = b'8\001'
35
+ _globals['_AGENTCONFIGMAP_CONFIGMAPENTRY']._options = None
36
+ _globals['_AGENTCONFIGMAP_CONFIGMAPENTRY']._serialized_options = b'8\001'
37
+ _globals['_AGENTTOSERVERFLAGS']._serialized_start=6233
38
+ _globals['_AGENTTOSERVERFLAGS']._serialized_end=6332
39
+ _globals['_SERVERTOAGENTFLAGS']._serialized_start=6334
40
+ _globals['_SERVERTOAGENTFLAGS']._serialized_end=6430
41
+ _globals['_SERVERCAPABILITIES']._serialized_start=6433
42
+ _globals['_SERVERCAPABILITIES']._serialized_end=6808
43
+ _globals['_PACKAGETYPE']._serialized_start=6810
44
+ _globals['_PACKAGETYPE']._serialized_end=6872
45
+ _globals['_SERVERERRORRESPONSETYPE']._serialized_start=6875
46
+ _globals['_SERVERERRORRESPONSETYPE']._serialized_end=7018
47
+ _globals['_COMMANDTYPE']._serialized_start=7020
48
+ _globals['_COMMANDTYPE']._serialized_end=7058
49
+ _globals['_AGENTCAPABILITIES']._serialized_start=7061
50
+ _globals['_AGENTCAPABILITIES']._serialized_end=7684
51
+ _globals['_REMOTECONFIGSTATUSES']._serialized_start=7687
52
+ _globals['_REMOTECONFIGSTATUSES']._serialized_end=7843
53
+ _globals['_PACKAGESTATUSENUM']._serialized_start=7846
54
+ _globals['_PACKAGESTATUSENUM']._serialized_end=8007
55
+ _globals['_AGENTTOSERVER']._serialized_start=45
56
+ _globals['_AGENTTOSERVER']._serialized_end=873
57
+ _globals['_AGENTDISCONNECT']._serialized_start=875
58
+ _globals['_AGENTDISCONNECT']._serialized_end=892
59
+ _globals['_CONNECTIONSETTINGSREQUEST']._serialized_start=894
60
+ _globals['_CONNECTIONSETTINGSREQUEST']._serialized_end=988
61
+ _globals['_OPAMPCONNECTIONSETTINGSREQUEST']._serialized_start=990
62
+ _globals['_OPAMPCONNECTIONSETTINGSREQUEST']._serialized_end=1104
63
+ _globals['_CERTIFICATEREQUEST']._serialized_start=1106
64
+ _globals['_CERTIFICATEREQUEST']._serialized_end=1144
65
+ _globals['_SERVERTOAGENT']._serialized_start=1147
66
+ _globals['_SERVERTOAGENT']._serialized_end=1859
67
+ _globals['_OPAMPCONNECTIONSETTINGS']._serialized_start=1862
68
+ _globals['_OPAMPCONNECTIONSETTINGS']._serialized_end=2049
69
+ _globals['_TELEMETRYCONNECTIONSETTINGS']._serialized_start=2052
70
+ _globals['_TELEMETRYCONNECTIONSETTINGS']._serialized_end=2243
71
+ _globals['_OTHERCONNECTIONSETTINGS']._serialized_start=2246
72
+ _globals['_OTHERCONNECTIONSETTINGS']._serialized_end=2595
73
+ _globals['_OTHERCONNECTIONSETTINGS_OTHERSETTINGSENTRY']._serialized_start=2531
74
+ _globals['_OTHERCONNECTIONSETTINGS_OTHERSETTINGSENTRY']._serialized_end=2595
75
+ _globals['_HEADERS']._serialized_start=2597
76
+ _globals['_HEADERS']._serialized_end=2653
77
+ _globals['_HEADER']._serialized_start=2655
78
+ _globals['_HEADER']._serialized_end=2703
79
+ _globals['_TLSCERTIFICATE']._serialized_start=2705
80
+ _globals['_TLSCERTIFICATE']._serialized_end=2821
81
+ _globals['_CONNECTIONSETTINGSOFFERS']._serialized_start=2824
82
+ _globals['_CONNECTIONSETTINGSOFFERS']._serialized_end=3360
83
+ _globals['_CONNECTIONSETTINGSOFFERS_OTHERCONNECTIONSENTRY']._serialized_start=3255
84
+ _globals['_CONNECTIONSETTINGSOFFERS_OTHERCONNECTIONSENTRY']._serialized_end=3360
85
+ _globals['_PACKAGESAVAILABLE']._serialized_start=3363
86
+ _globals['_PACKAGESAVAILABLE']._serialized_end=3592
87
+ _globals['_PACKAGESAVAILABLE_PACKAGESENTRY']._serialized_start=3502
88
+ _globals['_PACKAGESAVAILABLE_PACKAGESENTRY']._serialized_end=3592
89
+ _globals['_PACKAGEAVAILABLE']._serialized_start=3595
90
+ _globals['_PACKAGEAVAILABLE']._serialized_end=3756
91
+ _globals['_DOWNLOADABLEFILE']._serialized_start=3758
92
+ _globals['_DOWNLOADABLEFILE']._serialized_end=3876
93
+ _globals['_SERVERERRORRESPONSE']._serialized_start=3879
94
+ _globals['_SERVERERRORRESPONSE']._serialized_end=4063
95
+ _globals['_RETRYINFO']._serialized_start=4065
96
+ _globals['_RETRYINFO']._serialized_end=4132
97
+ _globals['_SERVERTOAGENTCOMMAND']._serialized_start=4134
98
+ _globals['_SERVERTOAGENTCOMMAND']._serialized_end=4202
99
+ _globals['_AGENTDESCRIPTION']._serialized_start=4205
100
+ _globals['_AGENTDESCRIPTION']._serialized_end=4386
101
+ _globals['_COMPONENTHEALTH']._serialized_start=4389
102
+ _globals['_COMPONENTHEALTH']._serialized_end=4792
103
+ _globals['_COMPONENTHEALTH_COMPONENTHEALTHMAPENTRY']._serialized_start=4693
104
+ _globals['_COMPONENTHEALTH_COMPONENTHEALTHMAPENTRY']._serialized_end=4792
105
+ _globals['_EFFECTIVECONFIG']._serialized_start=4794
106
+ _globals['_EFFECTIVECONFIG']._serialized_end=4871
107
+ _globals['_REMOTECONFIGSTATUS']._serialized_start=4874
108
+ _globals['_REMOTECONFIGSTATUS']._serialized_end=5045
109
+ _globals['_PACKAGESTATUSES']._serialized_start=5048
110
+ _globals['_PACKAGESTATUSES']._serialized_end=5337
111
+ _globals['_PACKAGESTATUSES_PACKAGESENTRY']._serialized_start=5250
112
+ _globals['_PACKAGESTATUSES_PACKAGESENTRY']._serialized_end=5337
113
+ _globals['_PACKAGESTATUS']._serialized_start=5340
114
+ _globals['_PACKAGESTATUS']._serialized_end=5652
115
+ _globals['_AGENTIDENTIFICATION']._serialized_start=5654
116
+ _globals['_AGENTIDENTIFICATION']._serialized_end=5717
117
+ _globals['_AGENTREMOTECONFIG']._serialized_start=5719
118
+ _globals['_AGENTREMOTECONFIG']._serialized_end=5824
119
+ _globals['_AGENTCONFIGMAP']._serialized_start=5827
120
+ _globals['_AGENTCONFIGMAP']._serialized_end=6010
121
+ _globals['_AGENTCONFIGMAP_CONFIGMAPENTRY']._serialized_start=5920
122
+ _globals['_AGENTCONFIGMAP_CONFIGMAPENTRY']._serialized_end=6010
123
+ _globals['_AGENTCONFIGFILE']._serialized_start=6012
124
+ _globals['_AGENTCONFIGFILE']._serialized_end=6084
125
+ _globals['_CUSTOMCAPABILITIES']._serialized_start=6086
126
+ _globals['_CUSTOMCAPABILITIES']._serialized_end=6142
127
+ _globals['_CUSTOMMESSAGE']._serialized_start=6144
128
+ _globals['_CUSTOMMESSAGE']._serialized_end=6231
129
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,24 @@
1
+ import json
2
+ import logging
3
+ from opamp import opamp_pb2
4
+
5
+ def parse_first_message_to_resource_attributes(first_message_server_to_agent: opamp_pb2.ServerToAgent, logger: logging.Logger) -> dict:
6
+ config_map = first_message_server_to_agent.remote_config.config.config_map
7
+
8
+ if "SDK" not in config_map:
9
+ logger.error("SDK not found in config map, returning empty resource attributes")
10
+ return {}
11
+
12
+ try:
13
+ sdk_config = json.loads(config_map["SDK"].body)
14
+ except json.JSONDecodeError as e:
15
+ logger.error(f"Error decoding SDK config: {e}")
16
+ return {}
17
+
18
+ remote_resource_attributes = sdk_config.get('remoteResourceAttributes', [])
19
+
20
+ if not remote_resource_attributes:
21
+ logger.error('missing "remoteResourceAttributes" section in OpAMP server remote config on first server to agent message')
22
+ return {}
23
+
24
+ return {item['key']: item['value'] for item in remote_resource_attributes}
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,64 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="odigos-opentelemetry-python",
5
+ version='v0.1.2',
6
+ description="Odigos Initializer for Python OpenTelemetry Components",
7
+ author="Tamir David",
8
+ author_email="tamir@odigos.io",
9
+ packages=find_packages(include=["initializer", "initializer.*", "opamp", "opamp.*"]),
10
+ install_requires=[
11
+ "requests~=2.7",
12
+ 'protobuf>=3.19, <5.0',
13
+ "uuid7 == 0.1.0",
14
+ 'opentelemetry-distro==0.45b0',
15
+ 'opentelemetry-exporter-otlp-proto-http==1.24.0',
16
+ 'opentelemetry-instrumentation==0.45b0',
17
+ 'opentelemetry-instrumentation-aio-pika==0.45b0',
18
+ 'opentelemetry-instrumentation-aiohttp-client==0.45b0',
19
+ 'opentelemetry-instrumentation-aiopg==0.45b0',
20
+ 'opentelemetry-instrumentation-asgi==0.45b0',
21
+ 'opentelemetry-instrumentation-asyncio==0.45b0',
22
+ 'opentelemetry-instrumentation-asyncpg==0.45b0',
23
+ 'opentelemetry-instrumentation-boto==0.45b0',
24
+ 'opentelemetry-instrumentation-boto3sqs==0.45b0',
25
+ 'opentelemetry-instrumentation-botocore==0.45b0',
26
+ 'opentelemetry-instrumentation-cassandra==0.45b0',
27
+ 'opentelemetry-instrumentation-celery==0.45b0',
28
+ 'opentelemetry-instrumentation-confluent-kafka==0.45b0',
29
+ 'opentelemetry-instrumentation-dbapi==0.45b0',
30
+ 'opentelemetry-instrumentation-django==0.45b0',
31
+ 'opentelemetry-instrumentation-elasticsearch==0.45b0',
32
+ 'opentelemetry-instrumentation-falcon==0.45b0',
33
+ 'opentelemetry-instrumentation-fastapi==0.45b0',
34
+ 'opentelemetry-instrumentation-flask==0.45b0',
35
+ 'opentelemetry-instrumentation-grpc==0.45b0',
36
+ 'opentelemetry-instrumentation-httpx==0.45b0',
37
+ 'opentelemetry-instrumentation-jinja2==0.45b0',
38
+ 'opentelemetry-instrumentation-kafka-python==0.45b0',
39
+ 'opentelemetry-instrumentation-logging==0.45b0',
40
+ 'opentelemetry-instrumentation-mysql==0.45b0',
41
+ 'opentelemetry-instrumentation-mysqlclient==0.45b0',
42
+ 'opentelemetry-instrumentation-pika==0.45b0',
43
+ 'opentelemetry-instrumentation-psycopg==0.45b0',
44
+ 'opentelemetry-instrumentation-psycopg2==0.45b0',
45
+ 'opentelemetry-instrumentation-pymemcache==0.45b0',
46
+ 'opentelemetry-instrumentation-pymongo==0.45b0',
47
+ 'opentelemetry-instrumentation-pymysql==0.45b0',
48
+ 'opentelemetry-instrumentation-pyramid==0.45b0',
49
+ 'opentelemetry-instrumentation-redis==0.45b0',
50
+ 'opentelemetry-instrumentation-remoulade==0.45b0',
51
+ 'opentelemetry-instrumentation-requests==0.45b0',
52
+ 'opentelemetry-instrumentation-sklearn==0.45b0',
53
+ 'opentelemetry-instrumentation-sqlalchemy==0.45b0',
54
+ 'opentelemetry-instrumentation-sqlite3==0.45b0',
55
+ 'opentelemetry-instrumentation-starlette==0.45b0',
56
+ 'opentelemetry-instrumentation-system-metrics==0.45b0',
57
+ 'opentelemetry-instrumentation-tornado==0.45b0',
58
+ 'opentelemetry-instrumentation-tortoiseorm==0.45b0',
59
+ 'opentelemetry-instrumentation-urllib==0.45b0',
60
+ 'opentelemetry-instrumentation-urllib3==0.45b0',
61
+ 'opentelemetry-instrumentation-wsgi==0.45b0',
62
+ ],
63
+ python_requires=">=3.8",
64
+ )