mantisdk 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl
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.
Potentially problematic release.
This version of mantisdk might be problematic. Click here for more details.
- mantisdk/__init__.py +1 -1
- mantisdk/tracing/__init__.py +57 -0
- mantisdk/tracing/api.py +546 -0
- mantisdk/tracing/attributes.py +191 -0
- mantisdk/tracing/exporters/__init__.py +10 -0
- mantisdk/tracing/exporters/insight.py +202 -0
- mantisdk/tracing/init.py +371 -0
- mantisdk/tracing/instrumentors/__init__.py +15 -0
- mantisdk/tracing/instrumentors/claude_agent_sdk.py +591 -0
- mantisdk/tracing/instrumentors/instrumentation_principles.md +289 -0
- mantisdk/tracing/instrumentors/registry.py +313 -0
- {mantisdk-0.1.1.dist-info → mantisdk-0.1.2.dist-info}/METADATA +1 -1
- {mantisdk-0.1.1.dist-info → mantisdk-0.1.2.dist-info}/RECORD +16 -6
- {mantisdk-0.1.1.dist-info → mantisdk-0.1.2.dist-info}/WHEEL +0 -0
- {mantisdk-0.1.1.dist-info → mantisdk-0.1.2.dist-info}/entry_points.txt +0 -0
- {mantisdk-0.1.1.dist-info → mantisdk-0.1.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Copyright (c) Metis. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Semantic attributes for MantisDK tracing.
|
|
4
|
+
|
|
5
|
+
These attributes follow the Mantis Insight OTEL conventions, ensuring
|
|
6
|
+
spans are properly processed and displayed in the Insight dashboard.
|
|
7
|
+
|
|
8
|
+
The attributes are organized by namespace:
|
|
9
|
+
- insight.*: Primary namespace for Insight-specific attributes
|
|
10
|
+
- gen_ai.*: OpenTelemetry GenAI semantic conventions
|
|
11
|
+
- langfuse.*: Compatibility namespace for Langfuse SDK spans
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
# =============================================================================
|
|
15
|
+
# Insight Trace Attributes (Primary Namespace)
|
|
16
|
+
# =============================================================================
|
|
17
|
+
INSIGHT_TRACE_NAME = "insight.trace.name"
|
|
18
|
+
INSIGHT_TRACE_USER_ID = "insight.user.id"
|
|
19
|
+
INSIGHT_TRACE_SESSION_ID = "insight.session.id"
|
|
20
|
+
INSIGHT_TRACE_TAGS = "insight.trace.tags"
|
|
21
|
+
INSIGHT_TRACE_PUBLIC = "insight.trace.public"
|
|
22
|
+
INSIGHT_TRACE_METADATA = "insight.trace.metadata"
|
|
23
|
+
INSIGHT_TRACE_INPUT = "insight.trace.input"
|
|
24
|
+
INSIGHT_TRACE_OUTPUT = "insight.trace.output"
|
|
25
|
+
|
|
26
|
+
# =============================================================================
|
|
27
|
+
# Insight Observation Attributes (Primary Namespace)
|
|
28
|
+
# =============================================================================
|
|
29
|
+
INSIGHT_OBSERVATION_TYPE = "insight.observation.type"
|
|
30
|
+
INSIGHT_OBSERVATION_METADATA = "insight.observation.metadata"
|
|
31
|
+
INSIGHT_OBSERVATION_LEVEL = "insight.observation.level"
|
|
32
|
+
INSIGHT_OBSERVATION_STATUS_MESSAGE = "insight.observation.status_message"
|
|
33
|
+
INSIGHT_OBSERVATION_INPUT = "insight.observation.input"
|
|
34
|
+
INSIGHT_OBSERVATION_OUTPUT = "insight.observation.output"
|
|
35
|
+
INSIGHT_OBSERVATION_MODEL = "insight.observation.model.name"
|
|
36
|
+
INSIGHT_OBSERVATION_MODEL_PARAMETERS = "insight.observation.model.parameters"
|
|
37
|
+
|
|
38
|
+
# =============================================================================
|
|
39
|
+
# Insight General Attributes (Primary Namespace)
|
|
40
|
+
# =============================================================================
|
|
41
|
+
INSIGHT_ENVIRONMENT = "insight.environment"
|
|
42
|
+
INSIGHT_RELEASE = "insight.release"
|
|
43
|
+
INSIGHT_VERSION = "insight.version"
|
|
44
|
+
|
|
45
|
+
# =============================================================================
|
|
46
|
+
# Langfuse Trace Attributes (Compatibility)
|
|
47
|
+
# =============================================================================
|
|
48
|
+
LANGFUSE_TRACE_NAME = "langfuse.trace.name"
|
|
49
|
+
LANGFUSE_TRACE_USER_ID = "user.id"
|
|
50
|
+
LANGFUSE_TRACE_SESSION_ID = "session.id"
|
|
51
|
+
LANGFUSE_TRACE_TAGS = "langfuse.trace.tags"
|
|
52
|
+
LANGFUSE_TRACE_PUBLIC = "langfuse.trace.public"
|
|
53
|
+
LANGFUSE_TRACE_METADATA = "langfuse.trace.metadata"
|
|
54
|
+
LANGFUSE_TRACE_INPUT = "langfuse.trace.input"
|
|
55
|
+
LANGFUSE_TRACE_OUTPUT = "langfuse.trace.output"
|
|
56
|
+
|
|
57
|
+
# =============================================================================
|
|
58
|
+
# Langfuse Observation Attributes (Compatibility)
|
|
59
|
+
# =============================================================================
|
|
60
|
+
LANGFUSE_OBSERVATION_TYPE = "langfuse.observation.type"
|
|
61
|
+
LANGFUSE_OBSERVATION_METADATA = "langfuse.observation.metadata"
|
|
62
|
+
LANGFUSE_OBSERVATION_LEVEL = "langfuse.observation.level"
|
|
63
|
+
LANGFUSE_OBSERVATION_STATUS_MESSAGE = "langfuse.observation.status_message"
|
|
64
|
+
LANGFUSE_OBSERVATION_INPUT = "langfuse.observation.input"
|
|
65
|
+
LANGFUSE_OBSERVATION_OUTPUT = "langfuse.observation.output"
|
|
66
|
+
|
|
67
|
+
# =============================================================================
|
|
68
|
+
# Langfuse Generation Attributes (Compatibility)
|
|
69
|
+
# =============================================================================
|
|
70
|
+
LANGFUSE_OBSERVATION_COMPLETION_START_TIME = "langfuse.observation.completion_start_time"
|
|
71
|
+
LANGFUSE_OBSERVATION_MODEL = "langfuse.observation.model.name"
|
|
72
|
+
LANGFUSE_OBSERVATION_MODEL_PARAMETERS = "langfuse.observation.model.parameters"
|
|
73
|
+
LANGFUSE_OBSERVATION_USAGE_DETAILS = "langfuse.observation.usage_details"
|
|
74
|
+
LANGFUSE_OBSERVATION_COST_DETAILS = "langfuse.observation.cost_details"
|
|
75
|
+
LANGFUSE_OBSERVATION_PROMPT_NAME = "langfuse.observation.prompt.name"
|
|
76
|
+
LANGFUSE_OBSERVATION_PROMPT_VERSION = "langfuse.observation.prompt.version"
|
|
77
|
+
|
|
78
|
+
# =============================================================================
|
|
79
|
+
# Langfuse General Attributes (Compatibility)
|
|
80
|
+
# =============================================================================
|
|
81
|
+
LANGFUSE_ENVIRONMENT = "langfuse.environment"
|
|
82
|
+
LANGFUSE_RELEASE = "langfuse.release"
|
|
83
|
+
LANGFUSE_VERSION = "langfuse.version"
|
|
84
|
+
|
|
85
|
+
# =============================================================================
|
|
86
|
+
# OpenTelemetry GenAI Semantic Conventions
|
|
87
|
+
# https://opentelemetry.io/docs/specs/semconv/gen-ai/
|
|
88
|
+
# =============================================================================
|
|
89
|
+
GEN_AI_OPERATION_NAME = "gen_ai.operation.name"
|
|
90
|
+
GEN_AI_SYSTEM = "gen_ai.system"
|
|
91
|
+
GEN_AI_REQUEST_MODEL = "gen_ai.request.model"
|
|
92
|
+
GEN_AI_RESPONSE_MODEL = "gen_ai.response.model"
|
|
93
|
+
GEN_AI_REQUEST_TEMPERATURE = "gen_ai.request.temperature"
|
|
94
|
+
GEN_AI_REQUEST_MAX_TOKENS = "gen_ai.request.max_tokens"
|
|
95
|
+
GEN_AI_RESPONSE_FINISH_REASONS = "gen_ai.response.finish_reasons"
|
|
96
|
+
GEN_AI_CONVERSATION_ID = "gen_ai.conversation.id"
|
|
97
|
+
|
|
98
|
+
# GenAI Input/Output
|
|
99
|
+
GEN_AI_INPUT_MESSAGES = "gen_ai.input.messages"
|
|
100
|
+
GEN_AI_OUTPUT_MESSAGES = "gen_ai.output.messages"
|
|
101
|
+
|
|
102
|
+
# GenAI Usage
|
|
103
|
+
GEN_AI_USAGE_INPUT_TOKENS = "gen_ai.usage.input_tokens"
|
|
104
|
+
GEN_AI_USAGE_OUTPUT_TOKENS = "gen_ai.usage.output_tokens"
|
|
105
|
+
GEN_AI_USAGE_COST = "gen_ai.usage.cost"
|
|
106
|
+
|
|
107
|
+
# GenAI Tool Attributes
|
|
108
|
+
GEN_AI_TOOL_NAME = "gen_ai.tool.name"
|
|
109
|
+
GEN_AI_TOOL_CALL_ARGUMENTS = "gen_ai.tool.call.arguments"
|
|
110
|
+
GEN_AI_TOOL_CALL_RESULT = "gen_ai.tool.call.result"
|
|
111
|
+
|
|
112
|
+
# =============================================================================
|
|
113
|
+
# OpenInference Semantic Conventions
|
|
114
|
+
# https://github.com/Arize-ai/openinference
|
|
115
|
+
# =============================================================================
|
|
116
|
+
OPENINFERENCE_SPAN_KIND = "openinference.span.kind"
|
|
117
|
+
|
|
118
|
+
# LLM Attributes
|
|
119
|
+
LLM_MODEL_NAME = "llm.model_name"
|
|
120
|
+
LLM_INVOCATION_PARAMETERS = "llm.invocation_parameters"
|
|
121
|
+
LLM_INPUT_MESSAGES = "llm.input_messages"
|
|
122
|
+
LLM_OUTPUT_MESSAGES = "llm.output_messages"
|
|
123
|
+
LLM_TOKEN_COUNT_PROMPT = "llm.token_count.prompt"
|
|
124
|
+
LLM_TOKEN_COUNT_COMPLETION = "llm.token_count.completion"
|
|
125
|
+
LLM_TOKEN_COUNT_TOTAL = "llm.token_count.total"
|
|
126
|
+
|
|
127
|
+
# Input/Output (general)
|
|
128
|
+
INPUT_VALUE = "input.value"
|
|
129
|
+
OUTPUT_VALUE = "output.value"
|
|
130
|
+
|
|
131
|
+
# Tool Attributes
|
|
132
|
+
TOOL_NAME = "tool.name"
|
|
133
|
+
TOOL_DESCRIPTION = "tool.description"
|
|
134
|
+
TOOL_PARAMETERS = "tool.parameters"
|
|
135
|
+
|
|
136
|
+
# =============================================================================
|
|
137
|
+
# OpenInference Span Kind Values
|
|
138
|
+
# =============================================================================
|
|
139
|
+
SPAN_KIND_LLM = "LLM"
|
|
140
|
+
SPAN_KIND_TOOL = "TOOL"
|
|
141
|
+
SPAN_KIND_AGENT = "AGENT"
|
|
142
|
+
SPAN_KIND_CHAIN = "CHAIN"
|
|
143
|
+
SPAN_KIND_EMBEDDING = "EMBEDDING"
|
|
144
|
+
SPAN_KIND_RETRIEVER = "RETRIEVER"
|
|
145
|
+
SPAN_KIND_RERANKER = "RERANKER"
|
|
146
|
+
SPAN_KIND_GUARDRAIL = "GUARDRAIL"
|
|
147
|
+
SPAN_KIND_EVALUATOR = "EVALUATOR"
|
|
148
|
+
|
|
149
|
+
# =============================================================================
|
|
150
|
+
# OpenInference MIME Types
|
|
151
|
+
# =============================================================================
|
|
152
|
+
MIME_TYPE_TEXT = "text/plain"
|
|
153
|
+
MIME_TYPE_JSON = "application/json"
|
|
154
|
+
|
|
155
|
+
# =============================================================================
|
|
156
|
+
# OpenInference Extended Attributes
|
|
157
|
+
# =============================================================================
|
|
158
|
+
INPUT_MIME_TYPE = "input.mime_type"
|
|
159
|
+
OUTPUT_MIME_TYPE = "output.mime_type"
|
|
160
|
+
LLM_SYSTEM = "llm.system"
|
|
161
|
+
LLM_PROVIDER = "llm.provider"
|
|
162
|
+
|
|
163
|
+
# Session/User attributes (OpenInference convention)
|
|
164
|
+
SESSION_ID = "session.id"
|
|
165
|
+
USER_ID = "user.id"
|
|
166
|
+
|
|
167
|
+
# Langfuse trace-level session (alias for compatibility)
|
|
168
|
+
LANGFUSE_TRACE_SESSION_ID = "session.id"
|
|
169
|
+
|
|
170
|
+
# =============================================================================
|
|
171
|
+
# MantisDK Custom Attributes
|
|
172
|
+
# These are additional attributes specific to MantisDK instrumentation
|
|
173
|
+
# =============================================================================
|
|
174
|
+
MANTIS_LLM_THINKING = "mantis.llm.thinking"
|
|
175
|
+
MANTIS_LLM_COST_USD = "mantis.llm.cost_usd"
|
|
176
|
+
MANTIS_DURATION_MS = "mantis.duration_ms"
|
|
177
|
+
MANTIS_DURATION_API_MS = "mantis.duration_api_ms"
|
|
178
|
+
MANTIS_NUM_TURNS = "mantis.num_turns"
|
|
179
|
+
MANTIS_TOOL_IS_ERROR = "mantis.tool.is_error"
|
|
180
|
+
|
|
181
|
+
# =============================================================================
|
|
182
|
+
# Claude-Specific Attributes
|
|
183
|
+
# These capture Claude Agent SDK-specific data not covered by standard conventions
|
|
184
|
+
# =============================================================================
|
|
185
|
+
CLAUDE_API_ERROR = "claude.api_error"
|
|
186
|
+
CLAUDE_PARENT_TOOL_USE_ID = "claude.parent_tool_use_id"
|
|
187
|
+
CLAUDE_STRUCTURED_OUTPUT = "claude.structured_output"
|
|
188
|
+
CLAUDE_THINKING_SIGNATURE = "claude.thinking.signature"
|
|
189
|
+
CLAUDE_MESSAGE_UUID = "claude.message.uuid"
|
|
190
|
+
CLAUDE_SYSTEM_SUBTYPE = "claude.system.subtype"
|
|
191
|
+
CLAUDE_SYSTEM_DATA = "claude.system.data"
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Copyright (c) Metis. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Insight OTLP exporter for MantisDK tracing.
|
|
4
|
+
|
|
5
|
+
This module provides an OTLP/HTTP exporter configured for Mantis Insight,
|
|
6
|
+
with support for environment variable auto-detection and Basic Auth headers.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import base64
|
|
12
|
+
import logging
|
|
13
|
+
import os
|
|
14
|
+
from typing import Optional
|
|
15
|
+
|
|
16
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
# Environment variable names (INSIGHT_* prefix)
|
|
21
|
+
ENV_INSIGHT_HOST = "INSIGHT_HOST"
|
|
22
|
+
ENV_INSIGHT_PUBLIC_KEY = "INSIGHT_PUBLIC_KEY"
|
|
23
|
+
ENV_INSIGHT_SECRET_KEY = "INSIGHT_SECRET_KEY"
|
|
24
|
+
ENV_INSIGHT_OTLP_ENDPOINT = "INSIGHT_OTLP_ENDPOINT"
|
|
25
|
+
|
|
26
|
+
# Default OTLP endpoint path
|
|
27
|
+
DEFAULT_OTLP_PATH = "/api/public/otel/v1/traces"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class InsightOTLPExporter(OTLPSpanExporter):
|
|
31
|
+
"""OTLP exporter configured for Mantis Insight.
|
|
32
|
+
|
|
33
|
+
This exporter automatically handles Basic Auth header construction
|
|
34
|
+
from public/secret key pairs.
|
|
35
|
+
|
|
36
|
+
Example::
|
|
37
|
+
|
|
38
|
+
from mantisdk.tracing_claude.exporters import InsightOTLPExporter
|
|
39
|
+
|
|
40
|
+
exporter = InsightOTLPExporter(
|
|
41
|
+
host="https://insight.withmetis.ai",
|
|
42
|
+
public_key="pk-lf-...",
|
|
43
|
+
secret_key="sk-lf-...",
|
|
44
|
+
)
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
host: str,
|
|
50
|
+
public_key: str,
|
|
51
|
+
secret_key: str,
|
|
52
|
+
*,
|
|
53
|
+
endpoint: Optional[str] = None,
|
|
54
|
+
**kwargs,
|
|
55
|
+
):
|
|
56
|
+
"""Initialize the Insight OTLP exporter.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
host: The Insight server URL (e.g., "https://insight.withmetis.ai").
|
|
60
|
+
public_key: The public key for authentication (pk-lf-...).
|
|
61
|
+
secret_key: The secret key for authentication (sk-lf-...).
|
|
62
|
+
endpoint: Optional full OTLP endpoint URL. If not provided,
|
|
63
|
+
derived from host + DEFAULT_OTLP_PATH.
|
|
64
|
+
**kwargs: Additional arguments passed to OTLPSpanExporter.
|
|
65
|
+
"""
|
|
66
|
+
# Derive endpoint from host if not explicitly provided
|
|
67
|
+
if endpoint is None:
|
|
68
|
+
# Remove trailing slash if present
|
|
69
|
+
host = host.rstrip("/")
|
|
70
|
+
endpoint = f"{host}{DEFAULT_OTLP_PATH}"
|
|
71
|
+
|
|
72
|
+
# Construct Basic Auth header
|
|
73
|
+
credentials = f"{public_key}:{secret_key}"
|
|
74
|
+
encoded = base64.b64encode(credentials.encode("utf-8")).decode("utf-8")
|
|
75
|
+
auth_header = f"Basic {encoded}"
|
|
76
|
+
|
|
77
|
+
# Merge auth header with any user-provided headers
|
|
78
|
+
headers = kwargs.pop("headers", {}) or {}
|
|
79
|
+
headers["Authorization"] = auth_header
|
|
80
|
+
|
|
81
|
+
super().__init__(endpoint=endpoint, headers=headers, **kwargs)
|
|
82
|
+
|
|
83
|
+
self._insight_host = host
|
|
84
|
+
self._insight_public_key = public_key
|
|
85
|
+
# Don't store secret key in instance for security
|
|
86
|
+
|
|
87
|
+
logger.debug(
|
|
88
|
+
"InsightOTLPExporter initialized: endpoint=%s, public_key=%s",
|
|
89
|
+
endpoint,
|
|
90
|
+
public_key[:20] + "..." if len(public_key) > 20 else public_key,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def __repr__(self) -> str:
|
|
94
|
+
return (
|
|
95
|
+
f"InsightOTLPExporter("
|
|
96
|
+
f"host={self._insight_host!r}, "
|
|
97
|
+
f"public_key={self._insight_public_key[:10]}...)"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def insight(
|
|
102
|
+
*,
|
|
103
|
+
host: Optional[str] = None,
|
|
104
|
+
public_key: Optional[str] = None,
|
|
105
|
+
secret_key: Optional[str] = None,
|
|
106
|
+
endpoint: Optional[str] = None,
|
|
107
|
+
**kwargs,
|
|
108
|
+
) -> InsightOTLPExporter:
|
|
109
|
+
"""Factory function to create an Insight OTLP exporter.
|
|
110
|
+
|
|
111
|
+
This function supports both explicit configuration and environment variable
|
|
112
|
+
auto-detection. If any required parameter is not provided, it will be read
|
|
113
|
+
from the corresponding environment variable.
|
|
114
|
+
|
|
115
|
+
Environment variables:
|
|
116
|
+
- INSIGHT_HOST: The Insight server URL
|
|
117
|
+
- INSIGHT_PUBLIC_KEY: The public key for authentication
|
|
118
|
+
- INSIGHT_SECRET_KEY: The secret key for authentication
|
|
119
|
+
- INSIGHT_OTLP_ENDPOINT: Optional override for the OTLP endpoint
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
host: The Insight server URL. Falls back to INSIGHT_HOST env var.
|
|
123
|
+
public_key: The public key. Falls back to INSIGHT_PUBLIC_KEY env var.
|
|
124
|
+
secret_key: The secret key. Falls back to INSIGHT_SECRET_KEY env var.
|
|
125
|
+
endpoint: Optional full OTLP endpoint URL. Falls back to INSIGHT_OTLP_ENDPOINT.
|
|
126
|
+
**kwargs: Additional arguments passed to InsightOTLPExporter.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
Configured InsightOTLPExporter instance.
|
|
130
|
+
|
|
131
|
+
Raises:
|
|
132
|
+
ValueError: If required credentials are not provided and not found in env vars.
|
|
133
|
+
|
|
134
|
+
Example::
|
|
135
|
+
|
|
136
|
+
import mantisdk.tracing_claude as tracing
|
|
137
|
+
|
|
138
|
+
# Using environment variables
|
|
139
|
+
tracing.init(exporters=[tracing.insight_exporter()])
|
|
140
|
+
|
|
141
|
+
# Explicit configuration
|
|
142
|
+
tracing.init(exporters=[
|
|
143
|
+
tracing.insight_exporter(
|
|
144
|
+
host="https://insight.withmetis.ai",
|
|
145
|
+
public_key="pk-lf-...",
|
|
146
|
+
secret_key="sk-lf-...",
|
|
147
|
+
)
|
|
148
|
+
])
|
|
149
|
+
"""
|
|
150
|
+
# Read from env vars if not provided
|
|
151
|
+
host = host or os.environ.get(ENV_INSIGHT_HOST)
|
|
152
|
+
public_key = public_key or os.environ.get(ENV_INSIGHT_PUBLIC_KEY)
|
|
153
|
+
secret_key = secret_key or os.environ.get(ENV_INSIGHT_SECRET_KEY)
|
|
154
|
+
endpoint = endpoint or os.environ.get(ENV_INSIGHT_OTLP_ENDPOINT)
|
|
155
|
+
|
|
156
|
+
# Validate required parameters
|
|
157
|
+
missing = []
|
|
158
|
+
if not host:
|
|
159
|
+
missing.append(f"{ENV_INSIGHT_HOST} (or host parameter)")
|
|
160
|
+
if not public_key:
|
|
161
|
+
missing.append(f"{ENV_INSIGHT_PUBLIC_KEY} (or public_key parameter)")
|
|
162
|
+
if not secret_key:
|
|
163
|
+
missing.append(f"{ENV_INSIGHT_SECRET_KEY} (or secret_key parameter)")
|
|
164
|
+
|
|
165
|
+
if missing:
|
|
166
|
+
raise ValueError(
|
|
167
|
+
f"Missing required Insight configuration: {', '.join(missing)}. "
|
|
168
|
+
"Provide these values via function arguments or environment variables."
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
return InsightOTLPExporter(
|
|
172
|
+
host=host,
|
|
173
|
+
public_key=public_key,
|
|
174
|
+
secret_key=secret_key,
|
|
175
|
+
endpoint=endpoint,
|
|
176
|
+
**kwargs,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def detect_insight_config() -> tuple[Optional[str], Optional[str], Optional[str], Optional[str]]:
|
|
181
|
+
"""Detect Insight configuration from environment variables.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
Tuple of (host, public_key, secret_key, endpoint) where any value may be None
|
|
185
|
+
if the corresponding environment variable is not set.
|
|
186
|
+
"""
|
|
187
|
+
return (
|
|
188
|
+
os.environ.get(ENV_INSIGHT_HOST),
|
|
189
|
+
os.environ.get(ENV_INSIGHT_PUBLIC_KEY),
|
|
190
|
+
os.environ.get(ENV_INSIGHT_SECRET_KEY),
|
|
191
|
+
os.environ.get(ENV_INSIGHT_OTLP_ENDPOINT),
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def is_insight_configured() -> bool:
|
|
196
|
+
"""Check if Insight is configured via environment variables.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
True if all required environment variables are set.
|
|
200
|
+
"""
|
|
201
|
+
host, public_key, secret_key, _ = detect_insight_config()
|
|
202
|
+
return all([host, public_key, secret_key])
|