Skip to content

Commit 53c4522

Browse files
authored
Add Tracing (#203)
* add telemetry * better v1 cgroups * version bump and trace cli version * fix not accepting pathlike
1 parent 6b06e51 commit 53c4522

File tree

5 files changed

+79
-4
lines changed

5 files changed

+79
-4
lines changed

patchwork/app.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ def list_option_callback(ctx: click.Context, param: click.Parameter, value: str
115115
"data_format", "--format", type=click.Choice(["yaml", "json"]), default="json", help="Format of the output file."
116116
)
117117
@click.option("patched_api_key", "--patched_api_key", help="API key to use with the patched.codes service.")
118+
@click.option(
119+
"disable_telemetry", "--disable-telemetry", is_flag=True, help="Disable telemetry.", default=False
120+
)
118121
def cli(
119122
log: str,
120123
patchflow: str,
@@ -123,6 +126,7 @@ def cli(
123126
output: str | None,
124127
data_format: str,
125128
patched_api_key: str | None,
129+
disable_telemetry: bool,
126130
):
127131
if "::" in patchflow:
128132
module_path, _, patchflow_name = patchflow.partition("::")
@@ -187,7 +191,11 @@ def cli(
187191

188192
try:
189193
repo = Repo(Path.cwd(), search_parent_directories=True)
190-
with PatchedClient(inputs.get("patched_api_key")).patched_telemetry(patchflow_name, repo, {}):
194+
patched = PatchedClient(inputs.get("patched_api_key"))
195+
if not disable_telemetry:
196+
patched.send_public_telemetry(patchflow_name, inputs)
197+
198+
with patched.patched_telemetry(patchflow_name, repo, {}):
191199
patchflow_instance = patchflow_class(inputs)
192200
patchflow_instance.run()
193201
except Exception as e:

patchwork/common/client/patched.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1+
import asyncio
12
import atexit
23
import contextlib
4+
import hashlib
5+
import http.client
6+
import json
7+
import platform
38
import socket
49
import sys
10+
import uuid
11+
from importlib import metadata
12+
from threading import Thread
13+
from typing import Any
514

615
import click
716
import requests
@@ -10,7 +19,7 @@
1019
from requests.adapters import DEFAULT_POOLBLOCK, HTTPAdapter
1120
from urllib3 import HTTPConnectionPool, HTTPSConnectionPool, PoolManager
1221

13-
from patchwork.common.utils import get_current_branch
22+
from patchwork.common.utils import get_current_branch, is_container
1423
from patchwork.logger import logger
1524

1625

@@ -64,6 +73,7 @@ def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool
6473
class PatchedClient(click.ParamType):
6574
TOKEN_URL = "https://app.patched.codes/signin"
6675
DEFAULT_PATCH_URL = "https://patchwork.patched.codes"
76+
ALLOWED_TELEMETRY_KEYS = {"model",}
6777

6878
def __init__(self, access_token: str, url: str = DEFAULT_PATCH_URL):
6979
self.access_token = access_token
@@ -119,6 +129,41 @@ def test_token(self) -> bool:
119129

120130
return body["msg"] == "ok"
121131

132+
def __handle_telemetry_inputs(self, inputs: dict[str, Any]) -> dict:
133+
diff_keys = set(inputs.keys()).difference(self.ALLOWED_TELEMETRY_KEYS)
134+
135+
inputs_copy = inputs.copy()
136+
for key in diff_keys:
137+
inputs_copy[key] = True
138+
139+
return inputs_copy
140+
141+
async def _public_telemetry(self, patchflow: str, inputs: dict[str, Any]):
142+
requests.post(
143+
url=self.url + "/v1/telemetry/",
144+
headers={"Authorization": f"Bearer {self.access_token}"},
145+
json=dict(
146+
client_id=hashlib.sha256(str(uuid.getnode()).encode()).hexdigest(),
147+
patchflow=patchflow,
148+
inputs=self.__handle_telemetry_inputs(inputs),
149+
environment=dict(
150+
system=platform.system(),
151+
release=platform.release(),
152+
machine=platform.machine(),
153+
python_version=platform.python_version(),
154+
cli_version=metadata.version("patchwork-cli"),
155+
is_container=is_container(),
156+
),
157+
),
158+
)
159+
160+
def send_public_telemetry(self, patchflow: str, inputs: dict):
161+
try:
162+
_thread = Thread(target=asyncio.run, args=(self._public_telemetry(patchflow, inputs),))
163+
_thread.start()
164+
except Exception as e:
165+
logger.debug(f"Failed to send public telemetry: {e}")
166+
122167
@contextlib.contextmanager
123168
def patched_telemetry(self, patchflow: str, repo: Repo, inputs: dict):
124169
if not self.access_token:

patchwork/common/utils.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,24 @@ def get_current_branch(repo: Repo) -> Head:
166166

167167
def get_required_keys(cls: TypedDict) -> set:
168168
return getattr(cls, "__required_keys__", set())
169+
170+
171+
def is_container() -> bool:
172+
test_files = ["/.dockerenv", "/run/.containerenv"]
173+
if any(Path(file).exists() for file in test_files):
174+
return True
175+
176+
cgroup_v1 = Path("/proc/self/cgroup")
177+
if cgroup_v1.exists():
178+
with cgroup_v1.open() as f:
179+
lines = f.readlines()
180+
for line in lines:
181+
# format is `hierachy_id:controllers:pathname`
182+
# cgroup v2 is `0::/`
183+
hierachy_id, _, rest = line.partition(":")
184+
controllers, _, pathname = rest.partition(":")
185+
if hierachy_id != "0" and len(controllers) > 0:
186+
return True
187+
188+
# TODO: cgroup v2 detection
189+
return False

patchwork/steps/CallCode2Prompt/CallCode2Prompt.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import subprocess
3+
from pathlib import Path
34

45
from patchwork.logger import logger
56
from patchwork.step import Step
@@ -19,7 +20,7 @@ def __init__(self, inputs: dict):
1920
self.folder_path = inputs[FOLDER_PATH]
2021
self.filter = inputs.get("filter", None)
2122
self.suppress_comments = inputs.get("suppress_comments", False)
22-
self.code_file_path = str(self.folder_path / "README.md")
23+
self.code_file_path = str(Path(self.folder_path) / "README.md")
2324
# Check if the file exists
2425
if not os.path.exists(self.code_file_path):
2526
# The file does not exist, create it by opening it in append mode and then closing it

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "patchwork-cli"
3-
version = "0.0.16"
3+
version = "0.0.17"
44
description = ""
55
authors = ["patched.codes"]
66
license = "AGPL"

0 commit comments

Comments
 (0)