Skip to content

Commit fd5a6aa

Browse files
authored
Add an i/o error label to http metrics (#512)
This change modifies HTTP error-labeling to detect I/O errors and label them explicitly. Previously all I/O errors were reported as `unexpected`. Additionally, an `errno` label is included when possible. Fixes linkerd/linkerd2#4364
1 parent 0a8c546 commit fd5a6aa

File tree

8 files changed

+44
-10
lines changed

8 files changed

+44
-10
lines changed

Cargo.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@ dependencies = [
641641
"linkerd2-dns",
642642
"linkerd2-drain",
643643
"linkerd2-duplex",
644+
"linkerd2-errno",
644645
"linkerd2-error",
645646
"linkerd2-error-metrics",
646647
"linkerd2-error-respond",
@@ -856,6 +857,10 @@ dependencies = [
856857
"tracing",
857858
]
858859

860+
[[package]]
861+
name = "linkerd2-errno"
862+
version = "0.1.0"
863+
859864
[[package]]
860865
name = "linkerd2-error"
861866
version = "0.1.0"
@@ -1197,6 +1202,7 @@ dependencies = [
11971202
"libc",
11981203
"linkerd2-conditional",
11991204
"linkerd2-dns-name",
1205+
"linkerd2-errno",
12001206
"linkerd2-error",
12011207
"linkerd2-identity",
12021208
"linkerd2-io",

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ members = [
1919
"linkerd/drain",
2020
"linkerd/duplex",
2121
"linkerd/error",
22+
"linkerd/errno",
2223
"linkerd/error-metrics",
2324
"linkerd/error-respond",
2425
"linkerd/exp-backoff",

linkerd/app/core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ linkerd2-conditional = { path = "../../conditional" }
2929
linkerd2-dns = { path = "../../dns" }
3030
linkerd2-drain = { path = "../../drain" }
3131
linkerd2-duplex = { path = "../../duplex" }
32+
linkerd2-errno = { path = "../../errno" }
3233
linkerd2-error = { path = "../../error" }
3334
linkerd2-error-metrics = { path = "../../error-metrics" }
3435
linkerd2-error-respond = { path = "../../error-respond" }

linkerd/app/core/src/errors.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::proxy::identity;
22
use futures::{Async, Poll};
33
use http::{header::HeaderValue, StatusCode};
4+
use linkerd2_errno::Errno;
45
use linkerd2_error::Error;
56
use linkerd2_error_metrics as metrics;
67
use linkerd2_error_respond as respond;
@@ -30,6 +31,7 @@ pub enum Reason {
3031
DispatchTimeout,
3132
ResponseTimeout,
3233
IdentityRequired,
34+
Io(Option<Errno>),
3335
FailFast,
3436
Unexpected,
3537
}
@@ -295,23 +297,31 @@ impl std::fmt::Display for IdentityRequired {
295297

296298
impl std::error::Error for IdentityRequired {}
297299

298-
impl metrics::LabelError<Error> for LabelError {
299-
type Labels = Label;
300-
301-
fn label_error(&self, err: &Error) -> Self::Labels {
302-
let reason = if err.is::<ResponseTimeout>() {
300+
impl LabelError {
301+
fn reason(err: &(dyn std::error::Error + 'static)) -> Reason {
302+
if err.is::<ResponseTimeout>() {
303303
Reason::ResponseTimeout
304304
} else if err.is::<FailFastError>() {
305305
Reason::FailFast
306306
} else if err.is::<tower::timeout::error::Elapsed>() {
307307
Reason::DispatchTimeout
308308
} else if err.is::<IdentityRequired>() {
309309
Reason::IdentityRequired
310+
} else if let Some(e) = err.downcast_ref::<std::io::Error>() {
311+
Reason::Io(e.raw_os_error().map(Errno::from))
312+
} else if let Some(e) = err.source() {
313+
Self::reason(e)
310314
} else {
311315
Reason::Unexpected
312-
};
316+
}
317+
}
318+
}
313319

314-
(self.0, reason)
320+
impl metrics::LabelError<Error> for LabelError {
321+
type Labels = Label;
322+
323+
fn label_error(&self, err: &Error) -> Self::Labels {
324+
(self.0, Self::reason(err.as_ref()))
315325
}
316326
}
317327

@@ -325,9 +335,16 @@ impl metrics::FmtLabels for Reason {
325335
Reason::DispatchTimeout => "dispatch timeout",
326336
Reason::ResponseTimeout => "response timeout",
327337
Reason::IdentityRequired => "identity required",
338+
Reason::Io(_) => "i/o",
328339
Reason::Unexpected => "unexpected",
329340
}
330-
)
341+
)?;
342+
343+
if let Reason::Io(Some(errno)) = self {
344+
write!(f, ",errno=\"{}\"", errno)?;
345+
}
346+
347+
Ok(())
331348
}
332349
}
333350

linkerd/errno/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "linkerd2-errno"
3+
version = "0.1.0"
4+
authors = ["Linkerd Developers <[email protected]>"]
5+
edition = "2018"
6+
publish = false

linkerd/proxy/transport/src/metrics/errno.rs renamed to linkerd/errno/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![deny(warnings, rust_2018_idioms)]
2+
13
use std::fmt;
24

35
/// Represents a platform-agnostic system error for metrics labels.

linkerd/proxy/transport/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ futures = "0.1"
1919
indexmap = "1.0.0"
2020
linkerd2-conditional = { path = "../../conditional" }
2121
linkerd2-dns-name = { path = "../../dns/name" }
22+
linkerd2-errno = { path = "../../errno" }
2223
linkerd2-error = { path = "../../error" }
2324
linkerd2-identity = { path = "../../identity" }
2425
linkerd2-io = { path = "../../io" }

linkerd/proxy/transport/src/metrics/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use futures::{try_ready, Future, Poll};
22
use indexmap::IndexMap;
3+
use linkerd2_errno::Errno;
34
use linkerd2_metrics::{
45
latency, metrics, Counter, FmtLabels, FmtMetric, FmtMetrics, Gauge, Histogram, Metric,
56
};
@@ -10,10 +11,9 @@ use std::time::Instant;
1011
use tokio::io::{AsyncRead, AsyncWrite};
1112
use tracing::debug;
1213

13-
mod errno;
1414
mod io;
1515

16-
pub use self::{errno::Errno, io::Io};
16+
pub use self::io::Io;
1717

1818
metrics! {
1919
tcp_open_total: Counter { "Total count of opened connections" },

0 commit comments

Comments
 (0)