Skip to content

Commit 0ca5a49

Browse files
committed
Remove deployment arg
1 parent 11a57b1 commit 0ca5a49

21 files changed

+245
-228
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Graphsignal is an AI optimization platform, enabling developers to achieve faste
88

99
* Identify and optimize the most significant contributors to latency.
1010
* Analyze model API costs for deployments, models, sessions, or any custom tags.
11-
* Ensure optimal model configuration and inference performance for hosted models.
11+
* Ensure optimal inference performance and model configuration for hosted models.
1212
* Track errors and monitor APIs, compute, and GPU utilization.
1313

1414

@@ -33,9 +33,13 @@ Configure Graphsignal tracer by specifying your API key directly or via `GRAPHSI
3333
```python
3434
import graphsignal
3535

36-
graphsignal.configure(api_key='my-api-key', deployment='my-app')
36+
graphsignal.configure(api_key='my-api-key')
37+
# or pass the API key in GRAPHSIGNAL_API_KEY environment variable
3738
```
3839

40+
See [`configure()`](https://graphsignal.com/docs/reference/python-api/#graphsignalconfigure) API docs for all configuration parameters.
41+
42+
3943
To get an API key, sign up for a free account at [graphsignal.com](https://graphsignal.com). The key can then be found in your account's [Settings / API Keys](https://app.graphsignal.com/settings/api-keys) page.
4044

4145
Alternatively, you can add Graphsignal tracer from the command line, when running your module or script. Environment variables `GRAPHSIGNAL_API_KEY` and `GRAPHSIGNAL_DEPLOYMENT` must be set.

graphsignal/__init__.py

Lines changed: 61 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
from typing import Dict, Any, Union, Optional
1+
from typing import Dict, Any, Union, Optional, Type
22
import os
33
import logging
44
import atexit
5-
import functools
6-
import asyncio
7-
import time
85

96
from graphsignal.version import __version__
107
from graphsignal.tracer import Tracer
118
from graphsignal.spans import Span
12-
from graphsignal import client
139

1410
logger = logging.getLogger('graphsignal')
1511

@@ -23,66 +19,85 @@ def _check_configured():
2319
'Tracer not configured, call graphsignal.configure() first')
2420

2521

26-
def _check_and_set_arg(
27-
name, value, is_str=False, is_int=False, is_bool=False, is_kv=False, required=False, max_len=None):
28-
env_name = 'GRAPHSIGNAL_{0}'.format(name.upper())
22+
def _parse_env_param(name: str, value: Any, expected_type: Type) -> Any:
23+
if value is None:
24+
return None
2925

30-
if not value and env_name in os.environ:
31-
value = os.environ[env_name]
32-
if value:
33-
if is_str:
34-
if max_len and len(value) > max_len:
35-
raise ValueError('configure: invalid format, expected string with max length {0}: {1}'.format(max_len, name))
36-
if is_int:
37-
try:
38-
value = int(value)
39-
except:
40-
raise ValueError('configure: invalid format, expected integer: {0}'.format(name))
41-
elif is_bool:
42-
value = bool(value)
43-
elif is_kv:
44-
try:
45-
value = dict([el.strip(' ') for el in kv.split('=')] for kv in value.split(','))
46-
except:
47-
raise ValueError('configure: invalid format, expected comma-separated key-value list (k1=v1,k2=v2): {0}'.format(name))
26+
try:
27+
if expected_type == bool:
28+
return value if isinstance(value, bool) else str(value).lower() in ("true", "1", "yes")
29+
elif expected_type == int:
30+
return int(value)
31+
elif expected_type == float:
32+
return float(value)
33+
elif expected_type == str:
34+
return str(value)
35+
except (ValueError, TypeError):
36+
pass
4837

49-
if not value and required:
50-
raise ValueError('configure: missing argument: {0}'.format(name))
38+
raise ValueError(f"Invalid type for {name}: expected {expected_type.__name__}, got {type(value).__name__}")
5139

52-
return value
40+
41+
def _read_config_param(name: str, expected_type: Type, provided_value: Optional[Any] = None, required: bool = False) -> Any:
42+
# Check if the value was provided as an argument
43+
if provided_value is not None:
44+
return provided_value
45+
46+
# Check if the value was provided as an environment variable
47+
env_value = os.getenv(f'GRAPHSIGNAL_{name.upper()}')
48+
if env_value is None:
49+
if required:
50+
raise ValueError(f"Missing required argument: {name}")
51+
return None
52+
53+
# Parse the environment variable
54+
return _parse_env_param(name, env_value, expected_type)
55+
56+
57+
def _read_config_tags(provided_value: Optional[dict] = None, prefix: str = "GRAPHSIGNAL_TAG_") -> Dict[str, str]:
58+
# Check if the value was provided as an argument
59+
if provided_value is not None:
60+
return provided_value
61+
62+
# Check if the value was provided as an environment variable
63+
return {key[len(prefix):].lower(): value for key, value in os.environ.items() if key.startswith(prefix)}
5364

5465

5566
def configure(
56-
api_key: Optional[str] = None,
57-
api_url: Optional[str] = None,
58-
deployment: Optional[str] = None,
59-
tags: Optional[Dict[str, str]] = None,
60-
auto_instrument: Optional[bool] = True,
61-
record_payloads: Optional[bool] = True,
62-
profiling_rate: Optional[float] = 0.1,
63-
upload_on_shutdown: Optional[bool] = True,
64-
debug_mode: Optional[bool] = False) -> None:
67+
api_key: Optional[str] = None,
68+
api_url: Optional[str] = None,
69+
deployment: Optional[str] = None,
70+
tags: Optional[Dict[str, str]] = None,
71+
auto_instrument: Optional[bool] = True,
72+
record_payloads: Optional[bool] = True,
73+
profiling_rate: Optional[float] = 0.1,
74+
debug_mode: Optional[bool] = False
75+
) -> None:
6576
global _tracer
6677

6778
if _tracer:
68-
logger.warning('Tracer already configured')
79+
logger.warning("Tracer already configured")
6980
return
7081

71-
debug_mode = _check_and_set_arg('debug_mode', debug_mode, is_bool=True)
72-
api_key = _check_and_set_arg('api_key', api_key, is_str=True, required=True)
73-
api_url = _check_and_set_arg('api_url', api_url, is_str=True, required=False)
74-
deployment = _check_and_set_arg('deployment', deployment, is_str=True, required=True)
75-
tags = _check_and_set_arg('tags', tags, is_kv=True, required=False)
82+
api_key = _read_config_param("api_key", str, api_key, required=True)
83+
api_url = _read_config_param("api_url", str, api_url)
84+
tags = _read_config_tags(tags)
85+
auto_instrument = _read_config_param("auto_instrument", bool, auto_instrument)
86+
record_payloads = _read_config_param("record_payloads", bool, record_payloads)
87+
profiling_rate = _read_config_param("profiling_rate", float, profiling_rate)
88+
debug_mode = _read_config_param("debug_mode", bool, debug_mode)
89+
90+
# left for compatibility
91+
if deployment and isinstance(deployment, str):
92+
tags['deployment'] = deployment
7693

7794
_tracer = Tracer(
7895
api_key=api_key,
7996
api_url=api_url,
80-
deployment=deployment,
8197
tags=tags,
8298
auto_instrument=auto_instrument,
8399
record_payloads=record_payloads,
84100
profiling_rate=profiling_rate,
85-
upload_on_shutdown=upload_on_shutdown,
86101
debug_mode=debug_mode)
87102
_tracer.setup()
88103

graphsignal/recorders/openai_recorder.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,10 @@ def trace_chat_completion(self, span, args, kwargs, ret, exc):
183183
self.set_common_tags(span, 'chat/completions', params)
184184
if 'model' in params:
185185
span.set_tag('model', params['model'])
186-
187186
if 'reasoning_effort' in params:
188187
span.set_tag('reasoning_effort', params['reasoning_effort'])
188+
if 'max_completion_tokens' in params:
189+
span.set_tag('max_completion_tokens', params['max_completion_tokens'])
189190

190191
if 'stream' in params and params['stream']:
191192
if 'messages' in params:

graphsignal/tracer.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,10 @@ def __init__(
113113
self,
114114
api_key=None,
115115
api_url=None,
116-
deployment=None,
117116
tags=None,
118117
auto_instrument=True,
119118
record_payloads=True,
120119
profiling_rate=0.1,
121-
upload_on_shutdown=True,
122120
debug_mode=False):
123121
if debug_mode:
124122
logger.setLevel(logging.DEBUG)
@@ -127,24 +125,19 @@ def __init__(
127125

128126
if not api_key:
129127
raise ValueError('api_key is required')
130-
if not deployment:
131-
raise ValueError('deployment is required')
132128

133129
self.api_key = api_key
134130
if api_url:
135131
self.api_url = api_url
136132
else:
137133
self.api_url = 'https://api.graphsignal.com'
138-
self.deployment = deployment
139-
self.tags = dict(deployment=self.deployment)
140-
if tags:
141-
self.tags.update(tags)
134+
self.tags = {}
135+
self.tags.update(tags)
142136
self.context_tags = contextvars.ContextVar('graphsignal_context_tags', default={})
143137

144138
self.auto_instrument = auto_instrument
145139
self.record_payloads = record_payloads
146140
self.profiling_rate = profiling_rate if profiling_rate is not None else 0
147-
self.upload_on_shutdown = upload_on_shutdown
148141
self.debug_mode = debug_mode
149142

150143
self._metric_update_thread = None
@@ -160,6 +153,8 @@ def __init__(
160153
self.last_metric_upload_ts = int(self._process_start_ms / 1e3)
161154
self.last_log_upload_ts = int(self._process_start_ms / 1e3)
162155

156+
self.export_on_shutdown = True
157+
163158
def setup(self):
164159
self._uploader = Uploader()
165160
self._uploader.setup()
@@ -185,7 +180,7 @@ def shutdown(self):
185180
self._metric_update_thread.join()
186181
self._metric_update_thread = None
187182

188-
if self.upload_on_shutdown:
183+
if self.export_on_shutdown:
189184
if self._metric_store.has_unexported():
190185
metrics = self._metric_store.export()
191186
for metric in metrics:

graphsignal/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '0.16.1'
1+
__version__ = '0.16.2'

0 commit comments

Comments
 (0)