• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pantsbuild / pants / 25565075335

08 May 2026 03:47PM UTC coverage: 92.787% (-0.1%) from 92.887%
25565075335

push

github

web-flow
add OpenTelemetry backend for work unit reporting (#23284)

# Overview

Add a new `pants.backend.observability.opentelemetry` backend to report
work unit tracing to OpenTelemetry. The backend is based on
[shoalsoft-pants-opentelemetry-plugin](https://github.com/shoalsoft/shoalsoft-pants-opentelemetry-plugin)
with unnecessary compatibility code and "shoalsoft" branding removed.

Notes:
- This backend only reports Pants engine work units to OpenTelemetry; it
does not report tracing data for Pants rule code or Rust code.
- This backend does not support gRPC export due to fork safety issues
with the gRPC C library and Python. See
https://github.com/shoalsoft/shoalsoft-pants-opentelemetry-plugin/issues/84
and https://github.com/grpc/grpc/blob/master/doc/fork_support.md for
additional details.

# Lockfile

```
    Lockfile diff: 3rdparty/python/user_reqs.lock [python-default]

    ==                    Upgraded dependencies                     ==

      anyio                          4.12.1       -->   4.13.0
      certifi                        2026.1.4     -->   2026.4.22
      charset-normalizer             3.4.4        -->   3.4.7
      click                          8.3.1        -->   8.3.2
      cross-web                      0.4.1        -->   0.6.0
      cryptography                   46.0.5       -->   46.0.7
      graphql-core                   3.2.7        -->   3.2.8
      idna                           3.11         -->   3.12
      librt                          0.8.1        -->   0.9.0
      pydantic                       2.12.5       -->   2.13.3
      pydantic-core                  2.41.5       -->   2.46.3
      pygments                       2.19.2       -->   2.20.0
      pyjwt                          2.11.0       -->   2.12.1
      python-dotenv                  1.2.1        -->   1.2.2
      python-multipart               0.0.22       -->   0.0.26
      ujson                          5.11.0       -->   5.12.0

    ==                   ... (continued)

564 of 740 new or added lines in 12 files covered. (76.22%)

1 existing line in 1 file now uncovered.

92944 of 100169 relevant lines covered (92.79%)

4.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.32
/src/python/pants/backend/observability/opentelemetry/processor.py
1
# Copyright 2026 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
3✔
5

6
import datetime
3✔
7
import enum
3✔
8
from dataclasses import dataclass
3✔
9
from typing import Any, Mapping, Protocol
3✔
10

11
from pants.util.frozendict import FrozenDict
3✔
12

13

14
class Level(enum.Enum):
3✔
15
    DEBUG = "DEBUG"
3✔
16
    ERROR = "ERROR"
3✔
17
    INFO = "INFO"
3✔
18
    TRACE = "TRACE"
3✔
19
    WARN = "WARN"
3✔
20

21

22
@dataclass(frozen=True)
3✔
23
class IncompleteWorkunit:
3✔
24
    """An incomplete workunit which only knows its start time."""
25

26
    name: str
3✔
27
    span_id: str
3✔
28
    parent_ids: tuple[str, ...]
3✔
29
    level: Level
3✔
30
    description: str | None
3✔
31
    start_time: datetime.datetime
3✔
32

33
    @property
3✔
34
    def primary_parent_id(self) -> str | None:
3✔
NEW
35
        if len(self.parent_ids) > 0:
×
NEW
36
            return self.parent_ids[0]
×
NEW
37
        return None
×
38

39

40
@dataclass(frozen=True)
3✔
41
class Workunit(IncompleteWorkunit):
3✔
42
    """The final workunit which knows when it completed as well."""
43

44
    end_time: datetime.datetime
3✔
45
    metadata: FrozenDict[str, Any]
3✔
46

47

48
class ProcessorContext(Protocol):
3✔
49
    def get_metrics(self) -> Mapping[str, int]: ...
50

51

52
class Processor(Protocol):
3✔
53
    """Protocol for emitter implementations."""
54

55
    def initialize(self) -> None: ...
56

57
    def start_workunit(
58
        self, workunit: IncompleteWorkunit, *, context: ProcessorContext
59
    ) -> None: ...
60

61
    def complete_workunit(self, workunit: Workunit, *, context: ProcessorContext) -> None: ...
62

63
    def finish(
64
        self, timeout: datetime.timedelta | None = None, *, context: ProcessorContext
65
    ) -> None: ...
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc