Skip to content

Commit cb91d6d

Browse files
authored
feat(dylint): exempt test files from telemetry semconv lints (#453)
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
1 parent e71ce4e commit cb91d6d

9 files changed

Lines changed: 61 additions & 7 deletions

File tree

rsworkspace/crates/acp-nats/src/agent/test_support/tests.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ fn has_request_metric_returns_false_when_empty() {
5050
// Builds a histogram under a counter's name to prove the lookup rejects the
5151
// wrong instrument kind; that mismatch is the point, so the generated
5252
// `build_acp_requests` (a counter) cannot stand in here.
53-
#[cfg_attr(dylint_lib = "trogon_lints", allow(telemetry_metric_construction))]
5453
fn has_request_metric_returns_false_for_histogram_metric() {
5554
let (provider, exporter) = test_provider();
5655
let meter = provider.meter("test");
@@ -105,7 +104,6 @@ fn has_error_metric_rejects_wrong_reason() {
105104
// Builds a histogram under a counter's name to prove the lookup rejects the
106105
// wrong instrument kind; that mismatch is the point, so the generated
107106
// `build_acp_errors` (a counter) cannot stand in here.
108-
#[cfg_attr(dylint_lib = "trogon_lints", allow(telemetry_metric_construction))]
109107
fn has_error_metric_returns_false_for_histogram_metric() {
110108
let (provider, exporter) = test_provider();
111109
let meter = provider.meter("test");

rsworkspace/crates/trogon-telemetry/src/log/tests.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ fn platform_log_dir_returns_path_ending_with_service_name() {
4444
#[test]
4545
// Exercises the export pipeline with a throwaway resource attribute that has no
4646
// semantic-convention counterpart.
47-
#[cfg_attr(dylint_lib = "trogon_lints", allow(telemetry_key_value_literal))]
4847
fn init_provider_lifecycle() {
4948
let resource = opentelemetry_sdk::Resource::builder()
5049
.with_service_name("test-log")

rsworkspace/crates/trogon-telemetry/src/metric/tests.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use opentelemetry_sdk::Resource;
55
#[test]
66
// Exercises the export pipeline with a throwaway resource attribute that has no
77
// semantic-convention counterpart.
8-
#[cfg_attr(dylint_lib = "trogon_lints", allow(telemetry_key_value_literal))]
98
fn init_provider_returns_valid_provider() {
109
let resource = Resource::builder()
1110
.with_service_name("test-metric")

rsworkspace/crates/trogon-telemetry/src/trace/tests.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use opentelemetry_sdk::Resource;
55
#[test]
66
// Exercises the export pipeline with a throwaway resource attribute that has no
77
// semantic-convention counterpart.
8-
#[cfg_attr(dylint_lib = "trogon_lints", allow(telemetry_key_value_literal))]
98
fn init_provider_returns_valid_provider() {
109
let resource = Resource::builder()
1110
.with_service_name("test-trace")
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//! UI fixture proving `telemetry_key_value_literal` is suppressed in test files.
2+
//! The example is named `*_tests.rs`, so the same inline `KeyValue::new` string
3+
//! key that fires in `telemetry_key_value_literal.rs` produces no diagnostic
4+
//! here. Absent a `.stderr`, the harness asserts zero diagnostics.
5+
6+
use opentelemetry::KeyValue;
7+
8+
fn inline_key() -> KeyValue {
9+
KeyValue::new("messaging.system", "nats")
10+
}
11+
12+
fn main() {
13+
let _ = inline_key();
14+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//! UI fixture proving `telemetry_metric_construction` is suppressed in test
2+
//! files. The example is named `*_tests.rs`, so opening an instrument builder
3+
//! inline, which is denied in `telemetry_metric_construction.rs`, produces no
4+
//! diagnostic here. Absent a `.stderr`, the harness asserts zero diagnostics.
5+
6+
use opentelemetry::metrics::{Counter, Meter};
7+
8+
const ACP_REQUESTS: &str = "acp.requests";
9+
10+
fn inline_build(meter: &Meter) -> Counter<u64> {
11+
meter
12+
.u64_counter(ACP_REQUESTS)
13+
.with_description("Total number of ACP requests")
14+
.build()
15+
}
16+
17+
fn main() {
18+
let meter = opentelemetry::global::meter("fixture");
19+
let _ = inline_build(&meter);
20+
}

rsworkspace/dylints/trogon_lints/src/telemetry_key_value_literal.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_lint::LateContext;
55
use rustc_middle::ty;
66

77
use crate::TELEMETRY_KEY_VALUE_LITERAL;
8-
use crate::telemetry_literal::string_literal_span;
8+
use crate::telemetry_literal::{in_test_file, string_literal_span};
99

1010
#[derive(Default)]
1111
pub(crate) struct TelemetryKeyValueLiteral;
@@ -24,6 +24,9 @@ impl TelemetryKeyValueLiteral {
2424
if !callee_is_key_value_new(cx, callee) {
2525
return;
2626
}
27+
if in_test_file(cx, key_span) {
28+
return;
29+
}
2730

2831
span_lint_and_then(
2932
cx,

rsworkspace/dylints/trogon_lints/src/telemetry_literal.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use rustc_ast::LitKind;
22
use rustc_hir::{Expr, ExprKind};
33
use rustc_lint::LateContext;
44
use rustc_middle::ty;
5+
use rustc_span::{FileName, Span};
56

67
/// Every `opentelemetry` `Meter` method that opens an instrument builder, keyed
78
/// by the instrument name as its first argument. Shared by the metric lints.
@@ -34,6 +35,24 @@ pub(crate) fn string_literal_span(expr: &Expr<'_>) -> Option<rustc_span::Span> {
3435
}
3536
}
3637

38+
/// Whether `span` originates in a test file, i.e. one whose stem is `tests` or
39+
/// ends in `_tests` (`tests.rs`, `parse_tests.rs`). Telemetry call sites in
40+
/// tests exercise the instruments directly rather than routing through the
41+
/// generated `trogon_semconv` constants, so the semconv lints exempt them.
42+
pub(crate) fn in_test_file(cx: &LateContext<'_>, span: Span) -> bool {
43+
let file = cx.tcx.sess.source_map().lookup_char_pos(span.lo()).file;
44+
let FileName::Real(real) = &file.name else {
45+
return false;
46+
};
47+
let Some(stem) = real
48+
.local_path()
49+
.and_then(|path| path.file_stem()?.to_str().map(str::to_owned))
50+
else {
51+
return false;
52+
};
53+
stem == "tests" || stem.ends_with("_tests")
54+
}
55+
3756
/// Whether the adjusted type of `receiver`, with references peeled, is the ADT
3857
/// `krate::...::ty_name`. Telemetry types are identified by their owning crate
3958
/// and name rather than a full def-path, mirroring how the checked crates avoid

rsworkspace/dylints/trogon_lints/src/telemetry_metric_construction.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_hir::{Expr, ExprKind};
44
use rustc_lint::LateContext;
55

66
use crate::TELEMETRY_METRIC_CONSTRUCTION;
7-
use crate::telemetry_literal::{INSTRUMENT_BUILDERS, receiver_is_type};
7+
use crate::telemetry_literal::{INSTRUMENT_BUILDERS, in_test_file, receiver_is_type};
88

99
#[derive(Default)]
1010
pub(crate) struct TelemetryMetricConstruction;
@@ -27,6 +27,9 @@ impl TelemetryMetricConstruction {
2727
if !receiver_is_type(cx, receiver, "opentelemetry", "Meter") {
2828
return;
2929
}
30+
if in_test_file(cx, expr.span) {
31+
return;
32+
}
3033

3134
span_lint_and_then(
3235
cx,

0 commit comments

Comments
 (0)