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

pantsbuild / pants / 21378504907

26 Jan 2026 11:48PM UTC coverage: 43.218% (-37.1%) from 80.269%
21378504907

Pull #23038

github

web-flow
Merge a9ec5051e into 09b8ecaa1
Pull Request #23038: remote cache logger - new plugin to help debug the remote cache

0 of 45 new or added lines in 1 file covered. (0.0%)

17212 existing lines in 540 files now uncovered.

26144 of 60493 relevant lines covered (43.22%)

0.86 hits per line

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

0.0
/src/python/pants/backend/tools/remote_cache_logger/rules.py
1
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
NEW
3
import csv
×
NEW
4
import logging
×
NEW
5
from typing import Any, Dict, Mapping, Tuple
×
6

NEW
7
from pants.engine.internals.scheduler import Workunit
×
NEW
8
from pants.engine.rules import collect_rules, rule
×
NEW
9
from pants.engine.streaming_workunit_handler import (
×
10
    StreamingWorkunitContext,
11
    WorkunitsCallback,
12
    WorkunitsCallbackFactory,
13
    WorkunitsCallbackFactoryRequest,
14
)
NEW
15
from pants.engine.unions import UnionRule
×
NEW
16
from pants.option.option_types import BoolOption, StrOption
×
NEW
17
from pants.option.subsystem import Subsystem
×
NEW
18
from pants.util.dirutil import safe_open
×
19

NEW
20
logger = logging.getLogger(__name__)
×
21

22

NEW
23
class RemoteCacheLoggerCallback(WorkunitsCallback):
×
24
    """Configuration for RemoteCacheLogger."""
25

NEW
26
    def __init__(self, wulogger: "RemoteCacheLogger"):
×
NEW
27
        self.wulogger = wulogger
×
NEW
28
        self._completed_workunits: Dict[str, Mapping[str, Any]] = {}
×
29

30

NEW
31
    @property
×
NEW
32
    def can_finish_async(self) -> bool:
×
NEW
33
        return False
×
34

NEW
35
    def __call__(
×
36
        self,
37
        *,
38
        completed_workunits: Tuple[Workunit, ...],
39
        started_workunits: Tuple[Workunit, ...],
40
        context: StreamingWorkunitContext,
41
        finished: bool = False,
42
        **kwargs: Any,
43
    ) -> None:
NEW
44
        for wu in completed_workunits:
×
NEW
45
            if wu["name"] == "remote_cache_read_speculation":
×
46
                # user_metadata entries are stored directly in metadata dict (not nested)
NEW
47
                metadata = wu.get("metadata", {})
×
NEW
48
                if not metadata or "request_description" not in metadata:
×
49
                    # Skip workunits with empty or incomplete metadata
NEW
50
                    continue
×
NEW
51
                self._completed_workunits[wu["span_id"]] = {
×
52
                    "description": metadata["request_description"],
53
                    "action_digest": metadata["action_digest"],
54
                    "outcome": metadata["outcome"],
55
                    "request": metadata["request"],
56
                }
NEW
57
        if finished:
×
NEW
58
            logger.debug(f"RemoteCacheLogger finished: captured {len(self._completed_workunits)} workunits")
×
NEW
59
            filepath = f"{self.wulogger.logdir}/{context.run_tracker.run_id}.csv"
×
NEW
60
            with safe_open(filepath, "w", newline="") as f:
×
NEW
61
                fieldnames = ["description", "action_digest", "outcome", "request"]
×
NEW
62
                writer = csv.DictWriter(f, fieldnames=fieldnames)
×
NEW
63
                writer.writeheader()
×
NEW
64
                writer.writerows(self._completed_workunits.values())
×
NEW
65
                logger.debug(f"Wrote {len(self._completed_workunits)} entries to {filepath}")
×
66

67

NEW
68
class RemoteCacheLoggerCallbackFactoryRequest:
×
69
    """A unique request type that is installed to trigger construction of our WorkunitsCallback."""
70

71

NEW
72
class RemoteCacheLogger(Subsystem):
×
NEW
73
    options_scope = "remote-cache-logger"
×
NEW
74
    help = "Remote Cache Logger subsystem. Useful for debugging remote cache."
×
75

NEW
76
    enabled = BoolOption("--enabled", default=False, help="Whether to enable remote cache logging.")
×
NEW
77
    logdir = StrOption("--logdir", default=".pants.d/workdir", help="Where to write the log to.")
×
78

79

NEW
80
@rule
×
NEW
81
def construct_callback(
×
82
    _: RemoteCacheLoggerCallbackFactoryRequest,
83
    wulogger: RemoteCacheLogger,
84
) -> WorkunitsCallbackFactory:
NEW
85
    return WorkunitsCallbackFactory(
×
86
        lambda: RemoteCacheLoggerCallback(wulogger) if wulogger.enabled else None
87
    )
88

89

NEW
90
def rules():
×
NEW
91
    return [
×
92
        UnionRule(WorkunitsCallbackFactoryRequest, RemoteCacheLoggerCallbackFactoryRequest),
93
        *collect_rules(),
94
    ]
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