Skip to content

Add consistent sampler #3668

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/core_contrib_test_0.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2932,3 +2932,33 @@ jobs:

- name: Run tests
run: tox -e py39-test-processor-baggage -- -ra

py39-test-sampler-consistent:
name: sampler-consistent
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout contrib repo @ SHA - ${{ env.CONTRIB_REPO_SHA }}
uses: actions/checkout@v4
with:
repository: open-telemetry/opentelemetry-python-contrib
ref: ${{ env.CONTRIB_REPO_SHA }}

- name: Checkout core repo @ SHA - ${{ env.CORE_REPO_SHA }}
uses: actions/checkout@v4
with:
repository: open-telemetry/opentelemetry-python
ref: ${{ env.CORE_REPO_SHA }}
path: opentelemetry-python

- name: Set up Python 3.9
uses: actions/setup-python@v5
with:
python-version: "3.9"
architecture: "x64"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -e py39-test-sampler-consistent -- -ra
19 changes: 19 additions & 0 deletions .github/workflows/lint_0.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1265,3 +1265,22 @@ jobs:

- name: Run tests
run: tox -e lint-processor-baggage

lint-sampler-consistent:
name: sampler-consistent
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -e lint-sampler-consistent
114 changes: 114 additions & 0 deletions .github/workflows/test_2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -961,3 +961,117 @@ jobs:

- name: Run tests
run: tox -e pypy3-test-processor-baggage -- -ra

py39-test-sampler-consistent_ubuntu-latest:
name: sampler-consistent 3.9 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.9
uses: actions/setup-python@v5
with:
python-version: "3.9"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -e py39-test-sampler-consistent -- -ra

py310-test-sampler-consistent_ubuntu-latest:
name: sampler-consistent 3.10 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.10
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -e py310-test-sampler-consistent -- -ra

py311-test-sampler-consistent_ubuntu-latest:
name: sampler-consistent 3.11 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -e py311-test-sampler-consistent -- -ra

py312-test-sampler-consistent_ubuntu-latest:
name: sampler-consistent 3.12 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -e py312-test-sampler-consistent -- -ra

py313-test-sampler-consistent_ubuntu-latest:
name: sampler-consistent 3.13 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -e py313-test-sampler-consistent -- -ra

pypy3-test-sampler-consistent_ubuntu-latest:
name: sampler-consistent pypy-3.9 Ubuntu
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
uses: actions/checkout@v4

- name: Set up Python pypy-3.9
uses: actions/setup-python@v5
with:
python-version: "pypy-3.9"

- name: Install tox
run: pip install tox-uv

- name: Run tests
run: tox -e pypy3-test-sampler-consistent -- -ra
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- `opentelemetry-sampler-consistent`: Add consistent samplers
([#3668](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3668))

## Version 1.36.0/0.57b0 (2025-07-29)

### Fixed
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ dependencies = [
"opentelemetry-instrumentation-wsgi",
"opentelemetry-propagator-ot-trace",
"opentelemetry-propagator-aws-xray",
"opentelemetry-sampler-consistent",
"opentelemetry-util-http",
"opentelemetry-instrumentation-vertexai[instruments]",
"opentelemetry-instrumentation-openai-v2[instruments]",
Expand Down Expand Up @@ -133,6 +134,7 @@ opentelemetry-instrumentation-urllib3 = { workspace = true }
opentelemetry-instrumentation-wsgi = { workspace = true }
opentelemetry-propagator-ot-trace = { workspace = true }
opentelemetry-propagator-aws-xray = { workspace = true }
opentelemetry-sampler-consistent = { workspace = true }
opentelemetry-util-http = { workspace = true }
opentelemetry-instrumentation-vertexai = { workspace = true }
opentelemetry-instrumentation-openai-v2 = { workspace = true }
Expand All @@ -145,6 +147,7 @@ members = [
"exporter/*",
"opentelemetry-instrumentation",
"propagator/*",
"sampler/*",
"util/opentelemetry-util-http",
]

Expand Down
39 changes: 39 additions & 0 deletions sampler/opentelemetry-sampler-consistent/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
OpenTelemetry Consistent Sampler
==========================================

|pypi|

.. |pypi| image:: https://badge.fury.io/py/opentelemetry-sampler-consistent.svg
:target: https://pypi.org/project/opentelemetry-sampler-consistent/

This library contains OpenTelemetry `Consistent Samplers <https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling/>`_
which allow backends to derive signals such as metrics from sampled traces.

Installation
------------

::

pip install opentelemetry-sampler-consistent

---------------------------

Usage example for ``opentelemetry-sampler-consistent``

.. code-block:: python

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sampler.consistent import parent_based, probability_based


trace.set_tracer_provider(
TracerProvider(
sampler=parent_based(probability_based(0.5)),
)
)

References
----------

* `OpenTelemetry Project <https://opentelemetry.io/>`_
45 changes: 45 additions & 0 deletions sampler/opentelemetry-sampler-consistent/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "opentelemetry-sampler-consistent"
dynamic = ["version"]
description = "Consistent Sampling for OpenTelemetry"
readme = "README.rst"
license = "Apache-2.0"
requires-python = ">=3.9"
authors = [
{ name = "OpenTelemetry Authors", email = "[email protected]" },
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = [
"opentelemetry-sdk ~= 1.12",
]

[project.urls]
Homepage = "https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/sampler/opentelemetry-sampler-consistent"
Repository = "https://github.com/open-telemetry/opentelemetry-python-contrib"

[tool.hatch.version]
path = "src/opentelemetry/sampler/consistent/version.py"

[tool.hatch.build.targets.sdist]
include = [
"/src",
"/tests",
]

[tool.hatch.build.targets.wheel]
packages = ["src/opentelemetry"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
__all__ = [
"ComposableSampler",
"ConsistentSampler",
"SamplingIntent",
"always_off",
"always_on",
"parent_based",
"probability_based",
]


from ._always_off import always_off
from ._always_on import always_on
from ._composable import ComposableSampler, SamplingIntent
from ._fixed_threshold import probability_based
from ._parent_based import parent_based
from ._sampler import ConsistentSampler
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from typing import Optional, Sequence

from opentelemetry.context import Context
from opentelemetry.trace import Link, SpanKind, TraceState
from opentelemetry.util.types import Attributes

from ._composable import ComposableSampler, SamplingIntent
from ._sampler import ConsistentSampler
from ._util import INVALID_THRESHOLD

_intent = SamplingIntent(
threshold=INVALID_THRESHOLD, adjusted_count_reliable=False
)


class ConsistentAlwaysOffSampler(ComposableSampler):
def sampling_intent(
self,
parent_ctx: Optional[Context],
name: str,
span_kind: Optional[SpanKind],
attributes: Attributes,
links: Optional[Sequence[Link]],
trace_state: Optional[TraceState] = None,
) -> SamplingIntent:
return _intent

def get_description(self) -> str:
return "ConsistentAlwaysOffSampler"


_always_off = ConsistentSampler(ConsistentAlwaysOffSampler())


def always_off() -> ConsistentSampler:
"""Returns a consistent sampler that does not sample any span."""
return _always_off
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from typing import Optional, Sequence

from opentelemetry.context import Context
from opentelemetry.trace import Link, SpanKind, TraceState
from opentelemetry.util.types import Attributes

from ._composable import ComposableSampler, SamplingIntent
from ._sampler import ConsistentSampler
from ._util import MIN_THRESHOLD

_intent = SamplingIntent(threshold=MIN_THRESHOLD)


class ConsistentAlwaysOnSampler(ComposableSampler):
def sampling_intent(
self,
parent_ctx: Optional[Context],
name: str,
span_kind: Optional[SpanKind],
attributes: Attributes,
links: Optional[Sequence[Link]],
trace_state: Optional[TraceState] = None,
) -> SamplingIntent:
return _intent

def get_description(self) -> str:
return "ConsistentAlwaysOnSampler"


_always_on = ConsistentSampler(ConsistentAlwaysOnSampler())


def always_on() -> ConsistentSampler:
"""Returns a consistent sampler that samples all spans."""
return _always_on
Loading