Line data Source code
1 : use std::{error::Error as StdError, fmt, io};
2 :
3 : use measured::FixedCardinalityLabel;
4 :
5 : /// Upcast (almost) any error into an opaque [`io::Error`].
6 0 : pub(crate) fn io_error(e: impl Into<Box<dyn StdError + Send + Sync>>) -> io::Error {
7 0 : io::Error::new(io::ErrorKind::Other, e)
8 0 : }
9 :
10 : /// A small combinator for pluggable error logging.
11 0 : pub(crate) fn log_error<E: fmt::Display>(e: E) -> E {
12 0 : tracing::error!("{e}");
13 0 : e
14 0 : }
15 :
16 : /// Marks errors that may be safely shown to a client.
17 : /// This trait can be seen as a specialized version of [`ToString`].
18 : ///
19 : /// NOTE: This trait should not be implemented for [`anyhow::Error`], since it
20 : /// is way too convenient and tends to proliferate all across the codebase,
21 : /// ultimately leading to accidental leaks of sensitive data.
22 : pub(crate) trait UserFacingError: ReportableError {
23 : /// Format the error for client, stripping all sensitive info.
24 : ///
25 : /// Although this might be a no-op for many types, it's highly
26 : /// recommended to override the default impl in case error type
27 : /// contains anything sensitive: various IDs, IP addresses etc.
28 : #[inline(always)]
29 0 : fn to_string_client(&self) -> String {
30 0 : self.to_string()
31 0 : }
32 : }
33 :
34 0 : #[derive(Copy, Clone, Debug, Eq, PartialEq, FixedCardinalityLabel)]
35 : #[label(singleton = "type")]
36 : pub enum ErrorKind {
37 : /// Wrong password, unknown endpoint, protocol violation, etc...
38 : User,
39 :
40 : /// Network error between user and proxy. Not necessarily user error
41 : #[label(rename = "clientdisconnect")]
42 : ClientDisconnect,
43 :
44 : /// Proxy self-imposed user rate limits
45 : #[label(rename = "ratelimit")]
46 : RateLimit,
47 :
48 : /// Proxy self-imposed service-wise rate limits
49 : #[label(rename = "serviceratelimit")]
50 : ServiceRateLimit,
51 :
52 : /// internal errors
53 : Service,
54 :
55 : /// Error communicating with control plane
56 : #[label(rename = "controlplane")]
57 : ControlPlane,
58 :
59 : /// Postgres error
60 : Postgres,
61 :
62 : /// Error communicating with compute
63 : Compute,
64 : }
65 :
66 : impl ErrorKind {
67 0 : pub(crate) fn to_metric_label(self) -> &'static str {
68 0 : match self {
69 0 : ErrorKind::User => "user",
70 0 : ErrorKind::ClientDisconnect => "clientdisconnect",
71 0 : ErrorKind::RateLimit => "ratelimit",
72 0 : ErrorKind::ServiceRateLimit => "serviceratelimit",
73 0 : ErrorKind::Service => "service",
74 0 : ErrorKind::ControlPlane => "controlplane",
75 0 : ErrorKind::Postgres => "postgres",
76 0 : ErrorKind::Compute => "compute",
77 : }
78 0 : }
79 : }
80 :
81 : pub(crate) trait ReportableError: fmt::Display + Send + 'static {
82 : fn get_error_kind(&self) -> ErrorKind;
83 : }
84 :
85 : impl ReportableError for tokio_postgres::error::Error {
86 0 : fn get_error_kind(&self) -> ErrorKind {
87 0 : if self.as_db_error().is_some() {
88 0 : ErrorKind::Postgres
89 : } else {
90 0 : ErrorKind::Compute
91 : }
92 0 : }
93 : }
|