Skip to content

Commit 6703eba

Browse files
authored
ekump/APMSP-1827 add warnings for panics (#915)
Add clippy warnings and allows for panic macros to most crates Add an extension crate for mutex in ddcommon to isolate the unwrap to one location in code to avoid the allow annotations. We aren't going to stop unwrapping mutexes anytime soon. Replace use of lazy_static with OnceLock for ddcommon, ddtelemetry, live-debugger, tools, sidecar
1 parent 6fab758 commit 6703eba

File tree

6 files changed

+49
-14
lines changed

6 files changed

+49
-14
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ hashbrown = { version = "0.14.3", default-features = false, features = ["inline-
1616
protobuf = { version = "3.5.0", default-features = false }
1717
ustr = { version = "1.0.0", default-features = false }
1818
fnv = { version = "1.0.7", default-features = false }
19-
lazy_static = { version = "1.5.0", default-features = false }
2019
reqwest = { version = "0.12.4", features = ["json", "http2", "rustls-tls"], default-features = false }
2120
serde = { version = "1.0.197", default-features = false, features = ["derive"] }
2221
serde_json = { version = "1.0.116", default-features = false, features = ["alloc"] }

src/datadog.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,28 @@
66
use crate::flusher::ShippingError;
77
use datadog_protos::metrics::SketchPayload;
88
use derive_more::{Display, Into};
9-
use lazy_static::lazy_static;
109
use protobuf::Message;
1110
use regex::Regex;
1211
use reqwest;
1312
use reqwest::{Client, Response};
1413
use serde::{Serialize, Serializer};
1514
use serde_json;
1615
use std::io::Write;
16+
use std::sync::OnceLock;
1717
use std::time::Duration;
1818
use tracing::{debug, error};
1919
use zstd::stream::write::Encoder;
2020

21-
lazy_static! {
22-
static ref SITE_RE: Regex = Regex::new(r"^[a-zA-Z0-9._:-]+$").expect("invalid regex");
23-
static ref URL_PREFIX_RE: Regex =
24-
Regex::new(r"^https?://[a-zA-Z0-9._:-]+$").expect("invalid regex");
21+
// TODO: Move to the more ergonomic LazyLock when MSRV is 1.80
22+
static SITE_RE: OnceLock<Regex> = OnceLock::new();
23+
fn get_site_re() -> &'static Regex {
24+
#[allow(clippy::expect_used)]
25+
SITE_RE.get_or_init(|| Regex::new(r"^[a-zA-Z0-9._:-]+$").expect("invalid regex"))
26+
}
27+
static URL_PREFIX_RE: OnceLock<Regex> = OnceLock::new();
28+
fn get_url_prefix_re() -> &'static Regex {
29+
#[allow(clippy::expect_used)]
30+
URL_PREFIX_RE.get_or_init(|| Regex::new(r"^https?://[a-zA-Z0-9._:-]+$").expect("invalid regex"))
2531
}
2632

2733
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Display, Into)]
@@ -36,7 +42,7 @@ impl Site {
3642
// Datadog sites are generally domain names. In particular, they shouldn't have any slashes
3743
// in them. We expect this to be coming from a `DD_SITE` environment variable or the `site`
3844
// config field.
39-
if SITE_RE.is_match(&site) {
45+
if get_site_re().is_match(&site) {
4046
Ok(Site(site))
4147
} else {
4248
Err(SiteError(site))
@@ -49,7 +55,7 @@ impl Site {
4955
pub struct UrlPrefixError(String);
5056

5157
fn validate_url_prefix(prefix: &str) -> Result<(), UrlPrefixError> {
52-
if URL_PREFIX_RE.is_match(prefix) {
58+
if get_url_prefix_re().is_match(prefix) {
5359
Ok(())
5460
} else {
5561
Err(UrlPrefixError(prefix.to_owned()))
@@ -111,6 +117,7 @@ impl MetricsIntakeUrlPrefix {
111117

112118
#[inline]
113119
fn new_expect_validated(validated_prefix: String) -> Self {
120+
#[allow(clippy::expect_used)]
114121
validate_url_prefix(&validated_prefix).expect("Invalid URL prefix");
115122

116123
Self(validated_prefix)

src/dogstatsd.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ impl BufferReader {
3535
// Max buffer size is configurable in Go Agent and the default is 8KB
3636
// https://github.com/DataDog/datadog-agent/blob/85939a62b5580b2a15549f6936f257e61c5aa153/pkg/config/config_template.yaml#L2154-L2158
3737
let mut buf = [0; 8192];
38+
39+
#[allow(clippy::expect_used)]
3840
let (amt, src) = socket
3941
.recv_from(&mut buf)
4042
.await
@@ -54,7 +56,9 @@ impl DogStatsD {
5456
cancel_token: tokio_util::sync::CancellationToken,
5557
) -> DogStatsD {
5658
let addr = format!("{}:{}", config.host, config.port);
59+
5760
// TODO (UDS socket)
61+
#[allow(clippy::expect_used)]
5862
let socket = tokio::net::UdpSocket::bind(addr)
5963
.await
6064
.expect("couldn't bind to address");
@@ -74,11 +78,14 @@ impl DogStatsD {
7478
}
7579

7680
async fn consume_statsd(&self) {
81+
#[allow(clippy::expect_used)]
7782
let (buf, src) = self
7883
.buffer_reader
7984
.read()
8085
.await
8186
.expect("didn't receive data");
87+
88+
#[allow(clippy::expect_used)]
8289
let msgs = std::str::from_utf8(&buf).expect("couldn't parse as string");
8390
debug!("Received message: {} from {}", msgs, src);
8491
let statsd_metric_strings = msgs.split('\n');
@@ -112,6 +119,7 @@ impl DogStatsD {
112119
})
113120
.collect();
114121
if !all_valid_metrics.is_empty() {
122+
#[allow(clippy::expect_used)]
115123
let mut guarded_aggregator = self.aggregator.lock().expect("lock poisoned");
116124
for a_valid_value in all_valid_metrics {
117125
let _ = guarded_aggregator.insert(a_valid_value);

src/flusher.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ impl Flusher {
3939

4040
pub async fn flush(&mut self) {
4141
let (all_series, all_distributions) = {
42+
#[allow(clippy::expect_used)]
4243
let mut aggregator = self.aggregator.lock().expect("lock poisoned");
4344
(
4445
aggregator.consume_metrics(),

src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/
22
// SPDX-License-Identifier: Apache-2.0
33

4+
#![cfg_attr(not(test), deny(clippy::panic))]
5+
#![cfg_attr(not(test), deny(clippy::unwrap_used))]
6+
#![cfg_attr(not(test), deny(clippy::expect_used))]
7+
#![cfg_attr(not(test), deny(clippy::todo))]
8+
#![cfg_attr(not(test), deny(clippy::unimplemented))]
9+
410
pub mod aggregator;
511
pub mod constants;
612
pub mod datadog;

src/metric.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,24 @@ use crate::errors::ParseError;
55
use crate::{constants, datadog};
66
use ddsketch_agent::DDSketch;
77
use fnv::FnvHasher;
8-
use lazy_static::lazy_static;
98
use protobuf::Chars;
109
use regex::Regex;
1110
use std::hash::{Hash, Hasher};
11+
use std::sync::OnceLock;
1212
use ustr::Ustr;
1313

1414
pub const EMPTY_TAGS: SortedTags = SortedTags { values: Vec::new() };
1515

1616
// https://docs.datadoghq.com/developers/dogstatsd/datagram_shell?tab=metrics#dogstatsd-protocol-v13
17-
lazy_static! {
18-
static ref METRIC_REGEX: Regex = Regex::new(
19-
r"^(?P<name>[^:]+):(?P<values>[^|]+)\|(?P<type>[a-zA-Z]+)(?:\|@(?P<sample_rate>[\d.]+))?(?:\|#(?P<tags>[^|]+))?(?:\|c:(?P<container_id>[^|]+))?(?:\|T(?P<timestamp>[^|]+))?$",
20-
).expect("Failed to create metric regex");
17+
static METRIC_REGEX: OnceLock<Regex> = OnceLock::new();
18+
fn get_metric_regex() -> &'static Regex {
19+
#[allow(clippy::expect_used)]
20+
METRIC_REGEX.get_or_init(|| {
21+
Regex::new(
22+
r"^(?P<name>[^:]+):(?P<values>[^|]+)\|(?P<type>[a-zA-Z]+)(?:\|@(?P<sample_rate>[\d.]+))?(?:\|#(?P<tags>[^|]+))?(?:\|c:(?P<container_id>[^|]+))?(?:\|T(?P<timestamp>[^|]+))?$",
23+
)
24+
.expect("Failed to create metric regex")
25+
})
2126
}
2227

2328
#[derive(Clone, Debug)]
@@ -181,6 +186,7 @@ impl Metric {
181186
tags: Option<SortedTags>,
182187
timestamp: Option<i64>,
183188
) -> Metric {
189+
#[allow(clippy::expect_used)]
184190
let parsed_timestamp = timestamp_to_bucket(timestamp.unwrap_or_else(|| {
185191
std::time::UNIX_EPOCH
186192
.elapsed()
@@ -204,6 +210,7 @@ impl Metric {
204210
// Round down to the nearest 10 seconds
205211
// to form a bucket of metric contexts aggregated per 10s
206212
pub fn timestamp_to_bucket(timestamp: i64) -> i64 {
213+
#[allow(clippy::expect_used)]
207214
let now_seconds: i64 = std::time::UNIX_EPOCH
208215
.elapsed()
209216
.expect("unable to poll clock, unrecoverable")
@@ -228,7 +235,7 @@ pub fn timestamp_to_bucket(timestamp: i64) -> i64 {
228235
/// example aj-test.increment:1|c|#user:aj-test from 127.0.0.1:50983
229236
pub fn parse(input: &str) -> Result<Metric, ParseError> {
230237
// TODO must enforce / exploit constraints given in `constants`.
231-
if let Some(caps) = METRIC_REGEX.captures(input) {
238+
if let Some(caps) = get_metric_regex().captures(input) {
232239
// unused for now
233240
// let sample_rate = caps.name("sample_rate").map(|m| m.as_str());
234241

@@ -238,8 +245,14 @@ pub fn parse(input: &str) -> Result<Metric, ParseError> {
238245
} else {
239246
tags = None;
240247
}
248+
249+
#[allow(clippy::unwrap_used)]
241250
let val = first_value(caps.name("values").unwrap().as_str())?;
251+
252+
#[allow(clippy::unwrap_used)]
242253
let t = caps.name("type").unwrap().as_str();
254+
255+
#[allow(clippy::expect_used)]
243256
let now = std::time::UNIX_EPOCH
244257
.elapsed()
245258
.expect("unable to poll clock, unrecoverable")
@@ -266,6 +279,7 @@ pub fn parse(input: &str) -> Result<Metric, ParseError> {
266279
return Err(ParseError::Raw(format!("Invalid metric type: {t}")));
267280
}
268281
};
282+
#[allow(clippy::unwrap_used)]
269283
let name = Ustr::from(caps.name("name").unwrap().as_str());
270284
let id = id(name, &tags, parsed_timestamp);
271285
return Ok(Metric {

0 commit comments

Comments
 (0)