mz_compute/render/
errors.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Helpers for handling errors encountered by operators.
11
12use mz_repr::Row;
13
14/// Used to make possibly-validating code generic: think of this as a kind of `MaybeResult`,
15/// specialized for use in compute.  Validation code will only run when the error constructor is
16/// Some.
17pub(super) trait MaybeValidatingRow<T, E> {
18    fn ok(t: T) -> Self;
19    fn into_error() -> Option<fn(E) -> Self>;
20}
21
22impl<E> MaybeValidatingRow<Row, E> for Row {
23    fn ok(t: Row) -> Self {
24        t
25    }
26
27    fn into_error() -> Option<fn(E) -> Self> {
28        None
29    }
30}
31
32impl<E> MaybeValidatingRow<(), E> for () {
33    fn ok(t: ()) -> Self {
34        t
35    }
36
37    fn into_error() -> Option<fn(E) -> Self> {
38        None
39    }
40}
41
42impl<E, R> MaybeValidatingRow<Vec<R>, E> for Vec<R> {
43    fn ok(t: Vec<R>) -> Self {
44        t
45    }
46
47    fn into_error() -> Option<fn(E) -> Self> {
48        None
49    }
50}
51
52impl<T, E> MaybeValidatingRow<T, E> for Result<T, E> {
53    fn ok(row: T) -> Self {
54        Ok(row)
55    }
56
57    fn into_error() -> Option<fn(E) -> Self> {
58        Some(Err)
59    }
60}
61
62/// Error logger to be used by rendering code.
63// TODO: Consider removing this struct.
64#[derive(Clone)]
65pub(super) struct ErrorLogger {
66    dataflow_name: String,
67}
68
69impl ErrorLogger {
70    pub fn new(dataflow_name: String) -> Self {
71        Self { dataflow_name }
72    }
73
74    /// Log the given error.
75    ///
76    /// The logging format is optimized for surfacing errors with Sentry:
77    ///  * `error` is logged at ERROR level and will appear as the error title in Sentry.
78    ///    We require it to be a static string, to ensure that Sentry always merges instances of
79    ///    the same error together.
80    ///  * `details` is logged at WARN level and will appear in the breadcrumbs.
81    ///    Put relevant dynamic information here.
82    ///
83    /// The message that's logged at WARN level has the format
84    ///   "[customer-data] {message} ({details})"
85    /// We include the [customer-data] tag out of the expectation that `details` will always
86    /// contain some sensitive customer data. We include the `message` to make it possible to match
87    /// the breadcrumbs to their associated error in Sentry.
88    ///
89    // TODO(database-issues#5362): Rethink or justify our error logging strategy.
90    pub fn log(&self, message: &'static str, details: &str) {
91        tracing::warn!(
92            dataflow = self.dataflow_name,
93            "[customer-data] {message} ({details})"
94        );
95        tracing::error!(message);
96    }
97
98    /// Like [`Self::log`], but panics in debug mode.
99    ///
100    /// Use this method to notify about errors that are certainly caused by bugs in Materialize.
101    pub fn soft_panic_or_log(&self, message: &'static str, details: &str) {
102        tracing::warn!(
103            dataflow = self.dataflow_name,
104            "[customer-data] {message} ({details})"
105        );
106        mz_ore::soft_panic_or_log!("{}", message);
107    }
108}