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