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}