Skip to content

Commit 1ab996c

Browse files
benjipelletierfacebook-github-bot
authored andcommitted
Add py bindings for otel metrics (#428)
Summary: Pull Request resolved: #428 Add counter, up_down_counter and gauge bindings in python so we can write metrics from py actors Differential Revision: D77751738
1 parent 92618a7 commit 1ab996c

File tree

3 files changed

+146
-1
lines changed

3 files changed

+146
-1
lines changed

hyperactor_extension/src/telemetry.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::cell::Cell;
1313
use hyperactor::clock::ClockKind;
1414
use hyperactor::clock::RealClock;
1515
use hyperactor::clock::SimClock;
16+
use hyperactor_telemetry::opentelemetry;
1617
use hyperactor_telemetry::swap_telemetry_clock;
1718
use pyo3::prelude::*;
1819
use pyo3::types::PyTraceback;
@@ -134,6 +135,73 @@ impl PySpan {
134135
}
135136
}
136137

138+
/// Add to a counter with the given name and attributes
139+
#[pyfunction]
140+
#[pyo3(signature = (name, value, attributes = None))]
141+
pub fn add_to_counter(
142+
name: String,
143+
value: u64,
144+
attributes: Option<Vec<(String, String)>>,
145+
) -> PyResult<()> {
146+
let kv_pairs: Vec<opentelemetry::KeyValue> = attributes
147+
.unwrap_or_default()
148+
.into_iter()
149+
.map(|(k, v)| opentelemetry::KeyValue::new(k, v))
150+
.collect();
151+
152+
println!("Added {} to counter {}", value, name);
153+
let counter = hyperactor_telemetry::meter("python")
154+
.u64_counter(name)
155+
.build();
156+
157+
counter.add(value, &kv_pairs);
158+
Ok(())
159+
}
160+
161+
/// Add to an up/down counter with the given name and attributes
162+
#[pyfunction]
163+
#[pyo3(signature = (name, value, attributes = None))]
164+
pub fn add_to_up_down_counter(
165+
name: String,
166+
value: i64,
167+
attributes: Option<Vec<(String, String)>>,
168+
) -> PyResult<()> {
169+
let kv_pairs: Vec<opentelemetry::KeyValue> = attributes
170+
.unwrap_or_default()
171+
.into_iter()
172+
.map(|(k, v)| opentelemetry::KeyValue::new(k, v))
173+
.collect();
174+
175+
let counter = hyperactor_telemetry::meter("python")
176+
.i64_up_down_counter(name)
177+
.build();
178+
179+
counter.add(value, &kv_pairs);
180+
Ok(())
181+
}
182+
183+
/// Record a value to a gauge with the given name and attributes
184+
#[pyfunction]
185+
#[pyo3(signature = (name, value, attributes = None))]
186+
pub fn add_to_gauge(
187+
name: String,
188+
value: f64,
189+
attributes: Option<Vec<(String, String)>>,
190+
) -> PyResult<()> {
191+
let kv_pairs: Vec<opentelemetry::KeyValue> = attributes
192+
.unwrap_or_default()
193+
.into_iter()
194+
.map(|(k, v)| opentelemetry::KeyValue::new(k, v))
195+
.collect();
196+
197+
let gauge = hyperactor_telemetry::meter("python")
198+
.f64_gauge(name)
199+
.build();
200+
201+
gauge.record(value, &kv_pairs);
202+
Ok(())
203+
}
204+
137205
use pyo3::Bound;
138206
use pyo3::types::PyModule;
139207

@@ -182,6 +250,28 @@ pub fn register_python_bindings(module: &Bound<'_, PyModule>) -> PyResult<()> {
182250
)?;
183251
module.add_function(use_sim_clock_fn)?;
184252

253+
// Register telemetry functions
254+
let add_to_counter_fn = wrap_pyfunction!(add_to_counter, module)?;
255+
add_to_counter_fn.setattr(
256+
"__module__",
257+
"monarch._rust_bindings.hyperactor_extension.telemetry",
258+
)?;
259+
module.add_function(add_to_counter_fn)?;
260+
261+
let add_to_up_down_counter_fn = wrap_pyfunction!(add_to_up_down_counter, module)?;
262+
add_to_up_down_counter_fn.setattr(
263+
"__module__",
264+
"monarch._rust_bindings.hyperactor_extension.telemetry",
265+
)?;
266+
module.add_function(add_to_up_down_counter_fn)?;
267+
268+
let add_to_gauge_fn = wrap_pyfunction!(add_to_gauge, module)?;
269+
add_to_gauge_fn.setattr(
270+
"__module__",
271+
"monarch._rust_bindings.hyperactor_extension.telemetry",
272+
)?;
273+
module.add_function(add_to_gauge_fn)?;
274+
185275
module.add_class::<PySpan>()?;
186276
Ok(())
187277
}

monarch_hyperactor/src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ use hyperactor::attrs::declare_attrs;
1616
// Declare monarch-specific configuration keys
1717
declare_attrs! {
1818
/// Use a single asyncio runtime for all Python actors, rather than one per actor
19-
pub attr SHARED_ASYNCIO_RUNTIME: bool = false;
19+
pub attr SHARED_ASYNCIO_RUNTIME: bool = true;
2020
}

python/monarch/_rust_bindings/hyperactor_extension/telemetry.pyi

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# LICENSE file in the root directory of this source tree.
66

77
import logging
8+
from typing import Optional
89

910
def forward_to_tracing(record: logging.LogRecord) -> None:
1011
"""
@@ -86,6 +87,60 @@ def use_sim_clock() -> None:
8687
"""
8788
...
8889

90+
def add_to_counter(
91+
name: str, value: int, attributes: Optional[list[tuple[str, str]]] = None
92+
) -> None:
93+
"""
94+
Add a value to a counter with the given name and attributes.
95+
96+
This function creates or uses an existing counter with the specified name
97+
and increments it by the given value with the provided attributes.
98+
99+
Args:
100+
- name (str): The name of the counter metric.
101+
- value (int): The value to add to the counter (must be non-negative).
102+
- attributes (Optional[list[tuple[str, str]]]): Optional list of key-value pairs to use as metric attributes.
103+
These attributes allow you to create different time series for the same counter.
104+
If None, no attributes will be added.
105+
"""
106+
...
107+
108+
def add_to_up_down_counter(
109+
name: str, value: int, attributes: Optional[list[tuple[str, str]]] = None
110+
) -> None:
111+
"""
112+
Add a value to an up/down counter with the given name and attributes.
113+
114+
This function creates or uses an existing up/down counter with the specified name
115+
and increments or decrements it by the given value with the provided attributes.
116+
117+
Args:
118+
- name (str): The name of the up/down counter metric.
119+
- value (int): The value to add to the counter (can be positive or negative).
120+
- attributes (Optional[list[tuple[str, str]]]): Optional list of key-value pairs to use as metric attributes.
121+
These attributes allow you to create different time series for the same counter.
122+
If None, no attributes will be added.
123+
"""
124+
...
125+
126+
def add_to_gauge(
127+
name: str, value: float, attributes: Optional[list[tuple[str, str]]] = None
128+
) -> None:
129+
"""
130+
Record a value to a gauge with the given name and attributes.
131+
132+
This function creates or uses an existing gauge with the specified name
133+
and sets it to the given value with the provided attributes.
134+
135+
Args:
136+
- name (str): The name of the gauge metric.
137+
- value (float): The value to record to the gauge.
138+
- attributes (Optional[list[tuple[str, str]]]): Optional list of key-value pairs to use as metric attributes.
139+
These attributes allow you to create different time series for the same gauge.
140+
If None, no attributes will be added.
141+
"""
142+
...
143+
89144
class PySpan:
90145
def __init__(self, name: str) -> None:
91146
"""

0 commit comments

Comments
 (0)