agentmark-sdk 0.1.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.
- agentmark_sdk-0.1.0/.gitignore +36 -0
- agentmark_sdk-0.1.0/PKG-INFO +24 -0
- agentmark_sdk-0.1.0/package.json +15 -0
- agentmark_sdk-0.1.0/pyproject.toml +50 -0
- agentmark_sdk-0.1.0/src/agentmark_sdk/__init__.py +71 -0
- agentmark_sdk-0.1.0/src/agentmark_sdk/config.py +12 -0
- agentmark_sdk-0.1.0/src/agentmark_sdk/decorator.py +182 -0
- agentmark_sdk-0.1.0/src/agentmark_sdk/sampler.py +60 -0
- agentmark_sdk-0.1.0/src/agentmark_sdk/sdk.py +252 -0
- agentmark_sdk-0.1.0/src/agentmark_sdk/serialize.py +33 -0
- agentmark_sdk-0.1.0/src/agentmark_sdk/trace.py +331 -0
- agentmark_sdk-0.1.0/tests/__init__.py +1 -0
- agentmark_sdk-0.1.0/tests/test_decorator.py +329 -0
- agentmark_sdk-0.1.0/tests/test_sampler.py +86 -0
- agentmark_sdk-0.1.0/tests/test_sdk.py +223 -0
- agentmark_sdk-0.1.0/tests/test_serialize.py +98 -0
- agentmark_sdk-0.1.0/tests/test_trace.py +281 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
node_modules
|
|
2
|
+
dist
|
|
3
|
+
.specs
|
|
4
|
+
.turbo
|
|
5
|
+
.yarn/install-state.gz
|
|
6
|
+
.yarn/releases/*
|
|
7
|
+
.yalc
|
|
8
|
+
yalc.lock
|
|
9
|
+
.env
|
|
10
|
+
*storybook.log
|
|
11
|
+
storybook-static
|
|
12
|
+
tmp-dev*/
|
|
13
|
+
.claude
|
|
14
|
+
|
|
15
|
+
# Nx
|
|
16
|
+
.nx/cache/
|
|
17
|
+
.nx/workspace-data/
|
|
18
|
+
|
|
19
|
+
# Python
|
|
20
|
+
__pycache__/
|
|
21
|
+
*.py[cod]
|
|
22
|
+
*$py.class
|
|
23
|
+
*.so
|
|
24
|
+
.Python
|
|
25
|
+
.venv/
|
|
26
|
+
*.egg-info/
|
|
27
|
+
.mypy_cache/
|
|
28
|
+
.ruff_cache/
|
|
29
|
+
.pytest_cache/
|
|
30
|
+
|
|
31
|
+
# AgentMark local development config (contains webhook secrets)
|
|
32
|
+
.agentmark/dev-config.json
|
|
33
|
+
|
|
34
|
+
# Speckit
|
|
35
|
+
specs/
|
|
36
|
+
.specify/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentmark-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AgentMark SDK for Python - Tracing and Observability
|
|
5
|
+
Author-email: AgentMark <support@agentmark.co>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: agentmark,llm,observability,opentelemetry,tracing
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: httpx>=0.25
|
|
18
|
+
Requires-Dist: opentelemetry-api>=1.20
|
|
19
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.20
|
|
20
|
+
Requires-Dist: opentelemetry-sdk>=1.20
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentmark-ai/sdk-python",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"postinstall": "node ../../scripts/setup-python-venv.js -e \".[dev]\"",
|
|
7
|
+
"test": "node ../../scripts/run-venv.js pytest",
|
|
8
|
+
"test:watch": "node ../../scripts/run-venv.js pytest --watch",
|
|
9
|
+
"lint": "node ../../scripts/run-venv.js ruff check src tests || echo Skipping lint: venv not set up",
|
|
10
|
+
"lint:fix": "node ../../scripts/run-venv.js ruff check --fix src tests",
|
|
11
|
+
"typecheck": "node ../../scripts/run-venv.js mypy src --strict",
|
|
12
|
+
"format": "node ../../scripts/run-venv.js ruff format src tests",
|
|
13
|
+
"clean": "shx rm -rf .venv dist *.egg-info .pytest_cache .mypy_cache .ruff_cache"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "agentmark-sdk"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "AgentMark SDK for Python - Tracing and Observability"
|
|
5
|
+
requires-python = ">=3.10"
|
|
6
|
+
license = { text = "MIT" }
|
|
7
|
+
authors = [{ name = "AgentMark", email = "support@agentmark.co" }]
|
|
8
|
+
keywords = ["agentmark", "llm", "tracing", "observability", "opentelemetry"]
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 3 - Alpha",
|
|
11
|
+
"Intended Audience :: Developers",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.10",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"opentelemetry-api>=1.20",
|
|
21
|
+
"opentelemetry-sdk>=1.20",
|
|
22
|
+
"opentelemetry-exporter-otlp-proto-http>=1.20",
|
|
23
|
+
"httpx>=0.25",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
dev = [
|
|
28
|
+
"pytest>=7.0",
|
|
29
|
+
"pytest-asyncio>=0.21",
|
|
30
|
+
"mypy>=1.0",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[build-system]
|
|
34
|
+
requires = ["hatchling"]
|
|
35
|
+
build-backend = "hatchling.build"
|
|
36
|
+
|
|
37
|
+
[tool.hatch.build.targets.wheel]
|
|
38
|
+
packages = ["src/agentmark_sdk"]
|
|
39
|
+
|
|
40
|
+
[tool.pytest.ini_options]
|
|
41
|
+
asyncio_mode = "auto"
|
|
42
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
43
|
+
testpaths = ["tests"]
|
|
44
|
+
python_files = ["test_*.py"]
|
|
45
|
+
python_functions = ["test_*"]
|
|
46
|
+
addopts = "-v --tb=short"
|
|
47
|
+
|
|
48
|
+
[tool.mypy]
|
|
49
|
+
strict = true
|
|
50
|
+
python_version = "3.10"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""AgentMark SDK for Python.
|
|
2
|
+
|
|
3
|
+
Provides OpenTelemetry-based tracing and observability for AI applications.
|
|
4
|
+
|
|
5
|
+
Example:
|
|
6
|
+
from agentmark_sdk import AgentMarkSDK, span, SpanOptions
|
|
7
|
+
|
|
8
|
+
# Initialize the SDK
|
|
9
|
+
sdk = AgentMarkSDK(api_key="sk-...", app_id="app_123")
|
|
10
|
+
sdk.init_tracing()
|
|
11
|
+
|
|
12
|
+
# Create a span around an operation
|
|
13
|
+
result = await span(
|
|
14
|
+
SpanOptions(name="my-operation", user_id="user-1"),
|
|
15
|
+
my_async_function,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# Auto-capture IO with decorator
|
|
19
|
+
from agentmark_sdk import observe, SpanKind
|
|
20
|
+
|
|
21
|
+
@observe(kind=SpanKind.TOOL)
|
|
22
|
+
async def my_tool(query: str) -> dict:
|
|
23
|
+
return {"result": "data"}
|
|
24
|
+
|
|
25
|
+
# Submit a score
|
|
26
|
+
await sdk.score(
|
|
27
|
+
resource_id=result.trace_id,
|
|
28
|
+
name="accuracy",
|
|
29
|
+
score=0.95,
|
|
30
|
+
)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from .config import (
|
|
34
|
+
AGENTMARK_KEY,
|
|
35
|
+
AGENTMARK_SCORE_ENDPOINT,
|
|
36
|
+
AGENTMARK_TRACE_ENDPOINT,
|
|
37
|
+
DEFAULT_BASE_URL,
|
|
38
|
+
METADATA_KEY,
|
|
39
|
+
)
|
|
40
|
+
from .decorator import SpanKind, observe
|
|
41
|
+
from .sampler import AgentmarkSampler
|
|
42
|
+
from .sdk import AgentMarkSDK
|
|
43
|
+
from .serialize import serialize_value
|
|
44
|
+
from .trace import SpanContext, SpanOptions, SpanResult, span, span_context, span_context_sync
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
# SDK
|
|
48
|
+
"AgentMarkSDK",
|
|
49
|
+
# Span utilities
|
|
50
|
+
"span",
|
|
51
|
+
"span_context",
|
|
52
|
+
"span_context_sync",
|
|
53
|
+
"observe",
|
|
54
|
+
"SpanOptions",
|
|
55
|
+
"SpanContext",
|
|
56
|
+
"SpanResult",
|
|
57
|
+
# Span kinds
|
|
58
|
+
"SpanKind",
|
|
59
|
+
# Serialization
|
|
60
|
+
"serialize_value",
|
|
61
|
+
# Sampler
|
|
62
|
+
"AgentmarkSampler",
|
|
63
|
+
# Config
|
|
64
|
+
"AGENTMARK_KEY",
|
|
65
|
+
"METADATA_KEY",
|
|
66
|
+
"AGENTMARK_TRACE_ENDPOINT",
|
|
67
|
+
"AGENTMARK_SCORE_ENDPOINT",
|
|
68
|
+
"DEFAULT_BASE_URL",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Configuration constants for AgentMark SDK."""
|
|
2
|
+
|
|
3
|
+
# API Endpoints
|
|
4
|
+
AGENTMARK_TRACE_ENDPOINT = "v1/traces"
|
|
5
|
+
AGENTMARK_SCORE_ENDPOINT = "v1/score"
|
|
6
|
+
|
|
7
|
+
# Default base URL
|
|
8
|
+
DEFAULT_BASE_URL = "https://api.agentmark.co"
|
|
9
|
+
|
|
10
|
+
# Span attribute prefixes
|
|
11
|
+
AGENTMARK_KEY = "agentmark"
|
|
12
|
+
METADATA_KEY = "agentmark.metadata"
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""Decorator-based tracing for automatic IO capture.
|
|
2
|
+
|
|
3
|
+
Provides the @observe decorator that auto-captures function arguments
|
|
4
|
+
as span input and return values as span output.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import functools
|
|
10
|
+
import inspect
|
|
11
|
+
from enum import Enum
|
|
12
|
+
from typing import Any, Callable, TypeVar, overload
|
|
13
|
+
|
|
14
|
+
from opentelemetry import trace as otel_trace
|
|
15
|
+
from opentelemetry.trace import StatusCode
|
|
16
|
+
|
|
17
|
+
from .config import AGENTMARK_KEY
|
|
18
|
+
from .serialize import serialize_value
|
|
19
|
+
|
|
20
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
21
|
+
|
|
22
|
+
# Attribute keys matching the gen_ai semantic conventions used by the adapter
|
|
23
|
+
INPUT_KEY = "gen_ai.request.input"
|
|
24
|
+
OUTPUT_KEY = "gen_ai.response.output"
|
|
25
|
+
SPAN_KIND_KEY = f"{AGENTMARK_KEY}.span.kind"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SpanKind(str, Enum):
|
|
29
|
+
"""Span kind for categorizing observed operations."""
|
|
30
|
+
|
|
31
|
+
FUNCTION = "function"
|
|
32
|
+
LLM = "llm"
|
|
33
|
+
TOOL = "tool"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _capture_inputs(
|
|
37
|
+
fn: Callable[..., Any],
|
|
38
|
+
args: tuple[Any, ...],
|
|
39
|
+
kwargs: dict[str, Any],
|
|
40
|
+
process_inputs: Callable[[dict[str, Any]], dict[str, Any]] | None,
|
|
41
|
+
) -> str | None:
|
|
42
|
+
"""Capture function arguments as a serialized input string."""
|
|
43
|
+
try:
|
|
44
|
+
sig = inspect.signature(fn)
|
|
45
|
+
bound = sig.bind(*args, **kwargs)
|
|
46
|
+
bound.apply_defaults()
|
|
47
|
+
inputs = dict(bound.arguments)
|
|
48
|
+
except (TypeError, ValueError):
|
|
49
|
+
# Fallback if signature binding fails
|
|
50
|
+
inputs = {"args": list(args), "kwargs": kwargs} if kwargs else {"args": list(args)}
|
|
51
|
+
|
|
52
|
+
if process_inputs is not None:
|
|
53
|
+
# Pass raw args (including self) to custom processor
|
|
54
|
+
inputs = process_inputs(inputs)
|
|
55
|
+
# Exclude self/cls for methods (after process_inputs so it can access self)
|
|
56
|
+
inputs.pop("self", None)
|
|
57
|
+
inputs.pop("cls", None)
|
|
58
|
+
|
|
59
|
+
return serialize_value(inputs)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _capture_output(
|
|
63
|
+
result: Any,
|
|
64
|
+
process_outputs: Callable[[Any], Any] | None,
|
|
65
|
+
) -> str | None:
|
|
66
|
+
"""Capture function return value as a serialized output string."""
|
|
67
|
+
output = result
|
|
68
|
+
if process_outputs is not None:
|
|
69
|
+
output = process_outputs(output)
|
|
70
|
+
return serialize_value(output)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@overload
|
|
74
|
+
def observe(_fn: F) -> F: ...
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@overload
|
|
78
|
+
def observe(
|
|
79
|
+
_fn: None = None,
|
|
80
|
+
*,
|
|
81
|
+
name: str | None = None,
|
|
82
|
+
kind: SpanKind = SpanKind.FUNCTION,
|
|
83
|
+
capture_input: bool = True,
|
|
84
|
+
capture_output: bool = True,
|
|
85
|
+
process_inputs: Callable[[dict[str, Any]], dict[str, Any]] | None = None,
|
|
86
|
+
process_outputs: Callable[[Any], Any] | None = None,
|
|
87
|
+
) -> Callable[[F], F]: ...
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def observe(
|
|
91
|
+
_fn: F | None = None,
|
|
92
|
+
*,
|
|
93
|
+
name: str | None = None,
|
|
94
|
+
kind: SpanKind = SpanKind.FUNCTION,
|
|
95
|
+
capture_input: bool = True,
|
|
96
|
+
capture_output: bool = True,
|
|
97
|
+
process_inputs: Callable[[dict[str, Any]], dict[str, Any]] | None = None,
|
|
98
|
+
process_outputs: Callable[[Any], Any] | None = None,
|
|
99
|
+
) -> F | Callable[[F], F]:
|
|
100
|
+
"""Decorator that auto-captures function IO as span attributes.
|
|
101
|
+
|
|
102
|
+
Supports both @observe and @observe() syntax, sync and async functions.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
name: Custom span name. Defaults to the function name.
|
|
106
|
+
kind: Span kind for categorization. Defaults to SpanKind.FUNCTION.
|
|
107
|
+
capture_input: Whether to capture function args as input. Default True.
|
|
108
|
+
capture_output: Whether to capture return value as output. Default True.
|
|
109
|
+
process_inputs: Optional transform applied to inputs before serialization.
|
|
110
|
+
process_outputs: Optional transform applied to output before serialization.
|
|
111
|
+
|
|
112
|
+
Example:
|
|
113
|
+
@observe
|
|
114
|
+
async def my_function(item_type: str) -> dict:
|
|
115
|
+
return {"result": "data"}
|
|
116
|
+
|
|
117
|
+
@observe(name="custom-name", kind=SpanKind.TOOL)
|
|
118
|
+
async def call_api(query: str) -> dict:
|
|
119
|
+
...
|
|
120
|
+
|
|
121
|
+
@observe(process_inputs=lambda inputs: {k: v for k, v in inputs.items() if k != "api_key"})
|
|
122
|
+
async def call_api(api_key: str, query: str) -> dict:
|
|
123
|
+
...
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
def decorator(fn: F) -> F:
|
|
127
|
+
span_name = name or fn.__name__
|
|
128
|
+
|
|
129
|
+
@functools.wraps(fn)
|
|
130
|
+
async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
131
|
+
tracer = otel_trace.get_tracer("agentmark")
|
|
132
|
+
with tracer.start_as_current_span(span_name) as span:
|
|
133
|
+
span.set_attribute(SPAN_KIND_KEY, kind.value)
|
|
134
|
+
|
|
135
|
+
if capture_input:
|
|
136
|
+
input_str = _capture_inputs(fn, args, kwargs, process_inputs)
|
|
137
|
+
if input_str is not None:
|
|
138
|
+
span.set_attribute(INPUT_KEY, input_str)
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
result = await fn(*args, **kwargs)
|
|
142
|
+
if capture_output:
|
|
143
|
+
output_str = _capture_output(result, process_outputs)
|
|
144
|
+
if output_str is not None:
|
|
145
|
+
span.set_attribute(OUTPUT_KEY, output_str)
|
|
146
|
+
span.set_status(StatusCode.OK)
|
|
147
|
+
return result
|
|
148
|
+
except Exception as e:
|
|
149
|
+
span.set_status(StatusCode.ERROR, str(e))
|
|
150
|
+
raise
|
|
151
|
+
|
|
152
|
+
@functools.wraps(fn)
|
|
153
|
+
def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
154
|
+
tracer = otel_trace.get_tracer("agentmark")
|
|
155
|
+
with tracer.start_as_current_span(span_name) as span:
|
|
156
|
+
span.set_attribute(SPAN_KIND_KEY, kind.value)
|
|
157
|
+
|
|
158
|
+
if capture_input:
|
|
159
|
+
input_str = _capture_inputs(fn, args, kwargs, process_inputs)
|
|
160
|
+
if input_str is not None:
|
|
161
|
+
span.set_attribute(INPUT_KEY, input_str)
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
result = fn(*args, **kwargs)
|
|
165
|
+
if capture_output:
|
|
166
|
+
output_str = _capture_output(result, process_outputs)
|
|
167
|
+
if output_str is not None:
|
|
168
|
+
span.set_attribute(OUTPUT_KEY, output_str)
|
|
169
|
+
span.set_status(StatusCode.OK)
|
|
170
|
+
return result
|
|
171
|
+
except Exception as e:
|
|
172
|
+
span.set_status(StatusCode.ERROR, str(e))
|
|
173
|
+
raise
|
|
174
|
+
|
|
175
|
+
if inspect.iscoroutinefunction(fn):
|
|
176
|
+
return async_wrapper # type: ignore[return-value]
|
|
177
|
+
return sync_wrapper # type: ignore[return-value]
|
|
178
|
+
|
|
179
|
+
# Support both @observe and @observe() syntax
|
|
180
|
+
if _fn is not None:
|
|
181
|
+
return decorator(_fn)
|
|
182
|
+
return decorator # type: ignore[return-value]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Custom sampler for AgentMark traces."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Sequence
|
|
6
|
+
|
|
7
|
+
from opentelemetry.context import Context
|
|
8
|
+
from opentelemetry.sdk.trace.sampling import (
|
|
9
|
+
Decision,
|
|
10
|
+
Sampler,
|
|
11
|
+
SamplingResult,
|
|
12
|
+
)
|
|
13
|
+
from opentelemetry.trace import Link, SpanKind
|
|
14
|
+
from opentelemetry.util.types import Attributes
|
|
15
|
+
|
|
16
|
+
# Span attributes that indicate internal framework spans to filter out
|
|
17
|
+
FILTERED_ATTRIBUTE_KEYS = ["next.span_name", "next.clientComponentLoadCount"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AgentmarkSampler(Sampler):
|
|
21
|
+
"""Custom sampler that filters out internal framework spans.
|
|
22
|
+
|
|
23
|
+
This sampler drops spans that have attributes indicating they are
|
|
24
|
+
internal framework spans (e.g., Next.js internals) that would add
|
|
25
|
+
noise to traces without providing useful debugging information.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def should_sample(
|
|
29
|
+
self,
|
|
30
|
+
parent_context: Context | None,
|
|
31
|
+
trace_id: int,
|
|
32
|
+
name: str,
|
|
33
|
+
kind: SpanKind | None = None,
|
|
34
|
+
attributes: Attributes | None = None,
|
|
35
|
+
links: Sequence[Link] | None = None,
|
|
36
|
+
) -> SamplingResult:
|
|
37
|
+
"""Determine whether to sample this span.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
parent_context: The parent context (if any).
|
|
41
|
+
trace_id: The trace ID.
|
|
42
|
+
name: The span name.
|
|
43
|
+
kind: The span kind.
|
|
44
|
+
attributes: Span attributes.
|
|
45
|
+
links: Span links.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
SamplingResult indicating whether to record/sample.
|
|
49
|
+
"""
|
|
50
|
+
# Check if any filtered attribute keys are present
|
|
51
|
+
if attributes:
|
|
52
|
+
for key in FILTERED_ATTRIBUTE_KEYS:
|
|
53
|
+
if key in attributes:
|
|
54
|
+
return SamplingResult(Decision.DROP)
|
|
55
|
+
|
|
56
|
+
return SamplingResult(Decision.RECORD_AND_SAMPLE)
|
|
57
|
+
|
|
58
|
+
def get_description(self) -> str:
|
|
59
|
+
"""Return a description of this sampler."""
|
|
60
|
+
return "AgentmarkSampler"
|