Skip to content

Commit 3f121a6

Browse files
authored
python: allow lines configuration (#199)
1 parent f26484b commit 3f121a6

File tree

6 files changed

+95
-39
lines changed

6 files changed

+95
-39
lines changed

pyroscope_backends/pyroscope_pyspy/src/lib.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use py_spy::{config::Config, sampler::Sampler};
1+
use py_spy::{config::Config, sampler::Sampler, Pid};
22
use pyroscope::{
33
backend::{
44
Backend, BackendConfig, BackendImpl, BackendUninitialized, Report, Rule, Ruleset,
@@ -14,7 +14,6 @@ use std::{
1414
},
1515
thread::JoinHandle,
1616
};
17-
use py_spy::Pid;
1817

1918
const LOG_TAG: &str = "Pyroscope::Pyspy";
2019

@@ -47,6 +46,8 @@ pub struct PyspyConfig {
4746
gil_only: bool,
4847
/// Profile native C extensions
4948
native: bool,
49+
50+
line_no: py_spy::config::LineNo,
5051
}
5152

5253
impl Default for PyspyConfig {
@@ -61,6 +62,7 @@ impl Default for PyspyConfig {
6162
oncpu: false,
6263
gil_only: false,
6364
native: false,
65+
line_no: py_spy::config::LineNo::LastInstruction,
6466
}
6567
}
6668
}
@@ -160,6 +162,13 @@ impl PyspyConfig {
160162
pub fn native(self, native: bool) -> Self {
161163
PyspyConfig { native, ..self }
162164
}
165+
166+
pub fn line_no(self, line_no: LineNo) -> Self {
167+
PyspyConfig {
168+
line_no: line_no.into(),
169+
..self
170+
}
171+
}
163172
}
164173

165174
/// Pyspy Backend
@@ -258,6 +267,7 @@ impl Backend for Pyspy {
258267
include_thread_ids: true,
259268
subprocesses: self.config.detect_subprocesses,
260269
gil_only: self.config.gil_only,
270+
lineno: self.config.line_no.clone().into(),
261271
duration,
262272
..Config::default()
263273
});
@@ -403,3 +413,22 @@ impl From<(py_spy::StackTrace, &BackendConfig)> for StackTraceWrapper {
403413
StackTraceWrapper(stacktrace)
404414
}
405415
}
416+
417+
// This is because we do not depdend on pyspy in ffikit
418+
// We probably need to change that and remove the glue
419+
// Not today
420+
pub enum LineNo {
421+
LastInstruction = 0,
422+
First = 1,
423+
NoLine = 2,
424+
}
425+
426+
impl Into<py_spy::config::LineNo> for LineNo {
427+
fn into(self) -> py_spy::config::LineNo {
428+
match self {
429+
LineNo::LastInstruction => py_spy::config::LineNo::LastInstruction,
430+
LineNo::First => py_spy::config::LineNo::First,
431+
LineNo::NoLine => py_spy::config::LineNo::NoLine,
432+
}
433+
}
434+
}

pyroscope_ffi/python/lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[package]
2+
# todo rename this, include python in the name
23
name = "pyroscope_ffi"
34
version = "0.1.0"
45
authors = ["Abid Omar <[email protected]>"]

pyroscope_ffi/python/lib/cbindgen.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ braces = "SameLine"
1717
tab_width = 2
1818
line_length = 80
1919

20+
2021
[parse]
2122
# Do not parse dependent crates
2223
parse_deps = false
24+
include = ["LineNoFFI"]
25+
26+
[export]
27+
include = ["LineNoFFI"]

pyroscope_ffi/python/lib/include/pyroscope_ffi.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212
#include <stdint.h>
1313
#include <stdlib.h>
1414

15+
typedef enum {
16+
LastInstruction = 0,
17+
First = 1,
18+
NoLine = 2,
19+
} LineNo;
20+
1521
bool initialize_logging(uint32_t logging_level);
1622

1723
bool initialize_agent(const char *application_name,
@@ -28,7 +34,8 @@ bool initialize_agent(const char *application_name,
2834
bool report_thread_name,
2935
const char *tags,
3036
const char *tenant_id,
31-
const char *http_headers_json);
37+
const char *http_headers_json,
38+
LineNo line_no);
3239

3340
bool drop_agent(void);
3441

pyroscope_ffi/python/lib/src/lib.rs

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use ffikit::Signal;
22
use pyroscope::backend::Tag;
3-
use pyroscope::PyroscopeAgent;
43
use pyroscope::pyroscope::ReportEncoding;
4+
use pyroscope::PyroscopeAgent;
55
use pyroscope_pyspy::{pyspy_backend, PyspyConfig};
66
use std::collections::hash_map::DefaultHasher;
77
use std::ffi::CStr;
@@ -15,22 +15,22 @@ pub extern "C" fn initialize_logging(logging_level: u32) -> bool {
1515
// Force rustc to display the log messages in the console.
1616
match logging_level {
1717
50 => {
18-
std::env::set_var("RUST_LOG", "off");
18+
unsafe { std::env::set_var("RUST_LOG", "off") };
1919
}
2020
40 => {
21-
std::env::set_var("RUST_LOG", "error");
21+
unsafe { std::env::set_var("RUST_LOG", "error") };
2222
}
2323
30 => {
24-
std::env::set_var("RUST_LOG", "warn");
24+
unsafe { std::env::set_var("RUST_LOG", "warn") };
2525
}
2626
20 => {
27-
std::env::set_var("RUST_LOG", "info");
27+
unsafe { std::env::set_var("RUST_LOG", "info") };
2828
}
2929
10 => {
30-
std::env::set_var("RUST_LOG", "debug");
30+
unsafe { std::env::set_var("RUST_LOG", "debug") };
3131
}
3232
_ => {
33-
std::env::set_var("RUST_LOG", "debug");
33+
unsafe { std::env::set_var("RUST_LOG", "debug") };
3434
}
3535
}
3636

@@ -41,21 +41,11 @@ pub extern "C" fn initialize_logging(logging_level: u32) -> bool {
4141

4242
#[no_mangle]
4343
pub extern "C" fn initialize_agent(
44-
application_name: *const c_char,
45-
server_address: *const c_char,
46-
auth_token: *const c_char,
47-
basic_auth_username: *const c_char,
48-
basic_auth_password: *const c_char,
49-
sample_rate: u32,
50-
detect_subprocesses: bool,
51-
oncpu: bool,
52-
gil_only: bool,
53-
report_pid: bool,
54-
report_thread_id: bool,
55-
report_thread_name: bool,
56-
tags: *const c_char,
57-
tenant_id: *const c_char,
58-
http_headers_json: *const c_char,
44+
application_name: *const c_char, server_address: *const c_char, auth_token: *const c_char,
45+
basic_auth_username: *const c_char, basic_auth_password: *const c_char, sample_rate: u32,
46+
detect_subprocesses: bool, oncpu: bool, gil_only: bool, report_pid: bool,
47+
report_thread_id: bool, report_thread_name: bool, tags: *const c_char,
48+
tenant_id: *const c_char, http_headers_json: *const c_char, line_no: LineNo
5949
) -> bool {
6050
// Initialize FFIKit
6151
let recv = ffikit::initialize_ffi().unwrap();
@@ -117,6 +107,7 @@ pub extern "C" fn initialize_agent(
117107
.detect_subprocesses(detect_subprocesses)
118108
.oncpu(oncpu)
119109
.native(false)
110+
.line_no(line_no.into())
120111
.gil_only(gil_only);
121112

122113
// Report the PID.
@@ -162,17 +153,15 @@ pub extern "C" fn initialize_agent(
162153
Ok(http_headers) => {
163154
agent_builder = agent_builder.http_headers(http_headers);
164155
}
165-
Err(e) => {
166-
match e {
167-
pyroscope::PyroscopeError::Json(e) => {
168-
log::error!(target: LOG_TAG, "parse_http_headers_json error {}", e);
169-
}
170-
pyroscope::PyroscopeError::AdHoc(e) => {
171-
log::error!(target: LOG_TAG, "parse_http_headers_json {}", e);
172-
}
173-
_ => {}
156+
Err(e) => match e {
157+
pyroscope::PyroscopeError::Json(e) => {
158+
log::error!(target: LOG_TAG, "parse_http_headers_json error {}", e);
174159
}
175-
}
160+
pyroscope::PyroscopeError::AdHoc(e) => {
161+
log::error!(target: LOG_TAG, "parse_http_headers_json {}", e);
162+
}
163+
_ => {}
164+
},
176165
}
177166

178167
// Build the agent.
@@ -291,3 +280,21 @@ fn string_to_tags<'a>(tags: &'a str) -> Vec<(&'a str, &'a str)> {
291280

292281
tags_vec
293282
}
283+
284+
#[repr(C)]
285+
#[derive(Debug)]
286+
pub enum LineNo {
287+
LastInstruction = 0,
288+
First = 1,
289+
NoLine = 2,
290+
}
291+
292+
impl Into<pyroscope_pyspy::LineNo> for LineNo {
293+
fn into(self) -> pyroscope_pyspy::LineNo {
294+
match self {
295+
LineNo::LastInstruction => pyroscope_pyspy::LineNo::LastInstruction,
296+
LineNo::First => pyroscope_pyspy::LineNo::First,
297+
LineNo::NoLine => pyroscope_pyspy::LineNo::NoLine,
298+
}
299+
}
300+
}

pyroscope_ffi/python/pyroscope/__init__.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22
import warnings
33
import logging
44
import json
5-
from collections import namedtuple
6-
from pyroscope._native import ffi, lib
7-
from contextlib import contextmanager
5+
from enum import Enum
86

7+
from pyroscope._native import lib
8+
from contextlib import contextmanager
9+
10+
class LineNo(Enum):
11+
LastInstruction = 0
12+
First = 1
13+
NoLine = 2
914

1015
def configure(
1116
app_name=None,
@@ -26,6 +31,7 @@ def configure(
2631
tags=None,
2732
tenant_id="",
2833
http_headers=None,
34+
line_no=LineNo.LastInstruction,
2935
):
3036

3137
if app_name is not None:
@@ -56,7 +62,8 @@ def configure(
5662
tags_to_string(tags).encode("UTF-8"),
5763
(tenant_id or "").encode("UTF-8"),
5864
http_headers_to_json(http_headers).encode("UTF-8"),
59-
)
65+
line_no.value
66+
)
6067

6168
def shutdown():
6269
drop = lib.drop_agent()

0 commit comments

Comments
 (0)