Skip to content

Commit 5c89071

Browse files
committed
Add consistent sampler
1 parent d2d136d commit 5c89071

25 files changed

+3443
-2396
lines changed

.github/workflows/core_contrib_test_0.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2932,3 +2932,33 @@ jobs:
29322932

29332933
- name: Run tests
29342934
run: tox -e py39-test-processor-baggage -- -ra
2935+
2936+
py39-test-sampler-consistent:
2937+
name: sampler-consistent
2938+
runs-on: ubuntu-latest
2939+
timeout-minutes: 30
2940+
steps:
2941+
- name: Checkout contrib repo @ SHA - ${{ env.CONTRIB_REPO_SHA }}
2942+
uses: actions/checkout@v4
2943+
with:
2944+
repository: open-telemetry/opentelemetry-python-contrib
2945+
ref: ${{ env.CONTRIB_REPO_SHA }}
2946+
2947+
- name: Checkout core repo @ SHA - ${{ env.CORE_REPO_SHA }}
2948+
uses: actions/checkout@v4
2949+
with:
2950+
repository: open-telemetry/opentelemetry-python
2951+
ref: ${{ env.CORE_REPO_SHA }}
2952+
path: opentelemetry-python
2953+
2954+
- name: Set up Python 3.9
2955+
uses: actions/setup-python@v5
2956+
with:
2957+
python-version: "3.9"
2958+
architecture: "x64"
2959+
2960+
- name: Install tox
2961+
run: pip install tox-uv
2962+
2963+
- name: Run tests
2964+
run: tox -e py39-test-sampler-consistent -- -ra

.github/workflows/lint_0.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,3 +1265,22 @@ jobs:
12651265

12661266
- name: Run tests
12671267
run: tox -e lint-processor-baggage
1268+
1269+
lint-sampler-consistent:
1270+
name: sampler-consistent
1271+
runs-on: ubuntu-latest
1272+
timeout-minutes: 30
1273+
steps:
1274+
- name: Checkout repo @ SHA - ${{ github.sha }}
1275+
uses: actions/checkout@v4
1276+
1277+
- name: Set up Python 3.13
1278+
uses: actions/setup-python@v5
1279+
with:
1280+
python-version: "3.13"
1281+
1282+
- name: Install tox
1283+
run: pip install tox-uv
1284+
1285+
- name: Run tests
1286+
run: tox -e lint-sampler-consistent

.github/workflows/test_2.yml

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -961,3 +961,117 @@ jobs:
961961

962962
- name: Run tests
963963
run: tox -e pypy3-test-processor-baggage -- -ra
964+
965+
py39-test-sampler-consistent_ubuntu-latest:
966+
name: sampler-consistent 3.9 Ubuntu
967+
runs-on: ubuntu-latest
968+
timeout-minutes: 30
969+
steps:
970+
- name: Checkout repo @ SHA - ${{ github.sha }}
971+
uses: actions/checkout@v4
972+
973+
- name: Set up Python 3.9
974+
uses: actions/setup-python@v5
975+
with:
976+
python-version: "3.9"
977+
978+
- name: Install tox
979+
run: pip install tox-uv
980+
981+
- name: Run tests
982+
run: tox -e py39-test-sampler-consistent -- -ra
983+
984+
py310-test-sampler-consistent_ubuntu-latest:
985+
name: sampler-consistent 3.10 Ubuntu
986+
runs-on: ubuntu-latest
987+
timeout-minutes: 30
988+
steps:
989+
- name: Checkout repo @ SHA - ${{ github.sha }}
990+
uses: actions/checkout@v4
991+
992+
- name: Set up Python 3.10
993+
uses: actions/setup-python@v5
994+
with:
995+
python-version: "3.10"
996+
997+
- name: Install tox
998+
run: pip install tox-uv
999+
1000+
- name: Run tests
1001+
run: tox -e py310-test-sampler-consistent -- -ra
1002+
1003+
py311-test-sampler-consistent_ubuntu-latest:
1004+
name: sampler-consistent 3.11 Ubuntu
1005+
runs-on: ubuntu-latest
1006+
timeout-minutes: 30
1007+
steps:
1008+
- name: Checkout repo @ SHA - ${{ github.sha }}
1009+
uses: actions/checkout@v4
1010+
1011+
- name: Set up Python 3.11
1012+
uses: actions/setup-python@v5
1013+
with:
1014+
python-version: "3.11"
1015+
1016+
- name: Install tox
1017+
run: pip install tox-uv
1018+
1019+
- name: Run tests
1020+
run: tox -e py311-test-sampler-consistent -- -ra
1021+
1022+
py312-test-sampler-consistent_ubuntu-latest:
1023+
name: sampler-consistent 3.12 Ubuntu
1024+
runs-on: ubuntu-latest
1025+
timeout-minutes: 30
1026+
steps:
1027+
- name: Checkout repo @ SHA - ${{ github.sha }}
1028+
uses: actions/checkout@v4
1029+
1030+
- name: Set up Python 3.12
1031+
uses: actions/setup-python@v5
1032+
with:
1033+
python-version: "3.12"
1034+
1035+
- name: Install tox
1036+
run: pip install tox-uv
1037+
1038+
- name: Run tests
1039+
run: tox -e py312-test-sampler-consistent -- -ra
1040+
1041+
py313-test-sampler-consistent_ubuntu-latest:
1042+
name: sampler-consistent 3.13 Ubuntu
1043+
runs-on: ubuntu-latest
1044+
timeout-minutes: 30
1045+
steps:
1046+
- name: Checkout repo @ SHA - ${{ github.sha }}
1047+
uses: actions/checkout@v4
1048+
1049+
- name: Set up Python 3.13
1050+
uses: actions/setup-python@v5
1051+
with:
1052+
python-version: "3.13"
1053+
1054+
- name: Install tox
1055+
run: pip install tox-uv
1056+
1057+
- name: Run tests
1058+
run: tox -e py313-test-sampler-consistent -- -ra
1059+
1060+
pypy3-test-sampler-consistent_ubuntu-latest:
1061+
name: sampler-consistent pypy-3.9 Ubuntu
1062+
runs-on: ubuntu-latest
1063+
timeout-minutes: 30
1064+
steps:
1065+
- name: Checkout repo @ SHA - ${{ github.sha }}
1066+
uses: actions/checkout@v4
1067+
1068+
- name: Set up Python pypy-3.9
1069+
uses: actions/setup-python@v5
1070+
with:
1071+
python-version: "pypy-3.9"
1072+
1073+
- name: Install tox
1074+
run: pip install tox-uv
1075+
1076+
- name: Run tests
1077+
run: tox -e pypy3-test-sampler-consistent -- -ra

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ dependencies = [
6363
"opentelemetry-instrumentation-wsgi",
6464
"opentelemetry-propagator-ot-trace",
6565
"opentelemetry-propagator-aws-xray",
66+
"opentelemetry-sampler-consistent",
6667
"opentelemetry-util-http",
6768
"opentelemetry-instrumentation-vertexai[instruments]",
6869
"opentelemetry-instrumentation-openai-v2[instruments]",
@@ -133,6 +134,7 @@ opentelemetry-instrumentation-urllib3 = { workspace = true }
133134
opentelemetry-instrumentation-wsgi = { workspace = true }
134135
opentelemetry-propagator-ot-trace = { workspace = true }
135136
opentelemetry-propagator-aws-xray = { workspace = true }
137+
opentelemetry-sampler-consistent = { workspace = true }
136138
opentelemetry-util-http = { workspace = true }
137139
opentelemetry-instrumentation-vertexai = { workspace = true }
138140
opentelemetry-instrumentation-openai-v2 = { workspace = true }
@@ -145,6 +147,7 @@ members = [
145147
"exporter/*",
146148
"opentelemetry-instrumentation",
147149
"propagator/*",
150+
"sampler/*",
148151
"util/opentelemetry-util-http",
149152
]
150153

sampler/opentelemetry-sampler-consistent/README.rst

Whitespace-only changes.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
[build-system]
2+
requires = ["hatchling"]
3+
build-backend = "hatchling.build"
4+
5+
[project]
6+
name = "opentelemetry-sampler-consistent"
7+
dynamic = ["version"]
8+
description = "Consistent Sampling for OpenTelemetry"
9+
readme = "README.rst"
10+
license = "Apache-2.0"
11+
requires-python = ">=3.9"
12+
authors = [
13+
{ name = "OpenTelemetry Authors", email = "[email protected]" },
14+
]
15+
classifiers = [
16+
"Development Status :: 5 - Production/Stable",
17+
"Intended Audience :: Developers",
18+
"License :: OSI Approved :: Apache Software License",
19+
"Programming Language :: Python",
20+
"Programming Language :: Python :: 3",
21+
"Programming Language :: Python :: 3.9",
22+
"Programming Language :: Python :: 3.10",
23+
"Programming Language :: Python :: 3.11",
24+
"Programming Language :: Python :: 3.12",
25+
"Programming Language :: Python :: 3.13",
26+
]
27+
dependencies = [
28+
"opentelemetry-sdk ~= 1.12",
29+
]
30+
31+
[project.urls]
32+
Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/sampler/opentelemetry-sampler-consistent"
33+
Repository = "https://github.com/open-telemetry/opentelemetry-python-contrib"
34+
35+
[tool.hatch.version]
36+
path = "src/opentelemetry/sampler/consistent/version.py"
37+
38+
[tool.hatch.build.targets.sdist]
39+
include = [
40+
"/src",
41+
"/tests",
42+
]
43+
44+
[tool.hatch.build.targets.wheel]
45+
packages = ["src/opentelemetry"]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
__all__ = [
2+
"ComposableSampler",
3+
"ConsistentSampler",
4+
"SamplingIntent",
5+
"always_off",
6+
"always_on",
7+
"parent_based",
8+
"probability_based",
9+
]
10+
11+
12+
from ._always_off import always_off
13+
from ._always_on import always_on
14+
from ._composable import ComposableSampler, SamplingIntent
15+
from ._fixed_threshold import probability_based
16+
from ._parent_based import parent_based
17+
from ._sampler import ConsistentSampler
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from typing import Optional, Sequence
2+
3+
from opentelemetry.context import Context
4+
from opentelemetry.trace import Link, SpanKind, TraceState
5+
from opentelemetry.util.types import Attributes
6+
7+
from ._composable import ComposableSampler, SamplingIntent
8+
from ._sampler import ConsistentSampler
9+
from ._util import INVALID_THRESHOLD
10+
11+
_intent = SamplingIntent(
12+
threshold=INVALID_THRESHOLD, adjusted_count_reliable=False
13+
)
14+
15+
16+
class ConsistentAlwaysOffSampler(ComposableSampler):
17+
def sampling_intent(
18+
self,
19+
parent_ctx: Optional[Context],
20+
name: str,
21+
span_kind: Optional[SpanKind],
22+
attributes: Attributes,
23+
links: Optional[Sequence[Link]],
24+
trace_state: Optional[TraceState] = None,
25+
) -> SamplingIntent:
26+
return _intent
27+
28+
def get_description(self) -> str:
29+
return "ConsistentAlwaysOffSampler"
30+
31+
32+
_always_off = ConsistentSampler(ConsistentAlwaysOffSampler())
33+
34+
35+
def always_off() -> ConsistentSampler:
36+
"""Returns a consistent sampler that does not sample any span."""
37+
return _always_off
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from typing import Optional, Sequence
2+
3+
from opentelemetry.context import Context
4+
from opentelemetry.trace import Link, SpanKind, TraceState
5+
from opentelemetry.util.types import Attributes
6+
7+
from ._composable import ComposableSampler, SamplingIntent
8+
from ._sampler import ConsistentSampler
9+
from ._util import MIN_THRESHOLD
10+
11+
_intent = SamplingIntent(threshold=MIN_THRESHOLD)
12+
13+
14+
class ConsistentAlwaysOnSampler(ComposableSampler):
15+
def sampling_intent(
16+
self,
17+
parent_ctx: Optional[Context],
18+
name: str,
19+
span_kind: Optional[SpanKind],
20+
attributes: Attributes,
21+
links: Optional[Sequence[Link]],
22+
trace_state: Optional[TraceState] = None,
23+
) -> SamplingIntent:
24+
return _intent
25+
26+
def get_description(self) -> str:
27+
return "ConsistentAlwaysOnSampler"
28+
29+
30+
_always_on = ConsistentSampler(ConsistentAlwaysOnSampler())
31+
32+
33+
def always_on() -> ConsistentSampler:
34+
"""Returns a consistent sampler that samples all spans."""
35+
return _always_on
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from dataclasses import dataclass, field
2+
from typing import Callable, Optional, Protocol, Sequence
3+
4+
from opentelemetry.context import Context
5+
from opentelemetry.trace import Link, SpanKind, TraceState
6+
from opentelemetry.util.types import Attributes
7+
8+
9+
@dataclass(frozen=True)
10+
class SamplingIntent:
11+
threshold: int
12+
adjusted_count_reliable: bool = field(default=True)
13+
attributes: Attributes = field(default=None)
14+
update_trace_state: Callable[[TraceState], TraceState] = field(
15+
default=lambda ts: ts
16+
)
17+
18+
19+
class ComposableSampler(Protocol):
20+
def sampling_intent(
21+
self,
22+
parent_ctx: Optional[Context],
23+
name: str,
24+
span_kind: Optional[SpanKind],
25+
attributes: Attributes,
26+
links: Optional[Sequence[Link]],
27+
trace_state: Optional[TraceState],
28+
) -> SamplingIntent:
29+
"""Returns information to make a consistent sampling decision."""
30+
...
31+
32+
def get_description(self) -> str:
33+
"""Returns a description of the sampler."""
34+
...

0 commit comments

Comments
 (0)