1use alloc::boxed::Box;
2use core::fmt::{Debug, Display};
3use core::num::NonZeroU32;
4use core::ops::{Deref, DerefMut};
5use downcast_rs::Downcast;
67#[cfg(feature = "std")]
8static GLOBAL_INSTRUMENTATION: std::sync::RwLock<fn() -> Option<Box<dyn Instrumentation>>> =
9 std::sync::RwLock::new(|| None);
1011/// A helper trait for opaque query representations
12/// which allows to get a `Display` and `Debug`
13/// representation of the underlying type without
14/// exposing type specific details
15pub trait DebugQuery: Debug + Display {}
1617impl<T, DB> DebugQueryfor crate::query_builder::DebugQuery<'_, T, DB> where Self: Debug + Display {}
1819/// A helper type that allows printing out str slices
20///
21/// This type is necessary because it's not possible
22/// to cast from a reference of a unsized type like `&str`
23/// to a reference of a trait object even if that
24/// type implements all necessary traits
25#[doc = " A helper type that allows printing out str slices"]
#[doc = ""]
#[doc = " This type is necessary because it\'s not possible"]
#[doc = " to cast from a reference of a unsized type like `&str`"]
#[doc = " to a reference of a trait object even if that"]
#[doc = " type implements all necessary traits"]
#[non_exhaustive]
pub struct StrQueryHelper<'query> {
s: &'query str,
}#[diesel_derives::__diesel_public_if(
26 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
27)]28pub(crate) struct StrQueryHelper<'query> {
29 s: &'query str,
30}
3132impl<'query> StrQueryHelper<'query> {
33/// Construct a new `StrQueryHelper`
34#[diesel_derives::__diesel_public_if(
35 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
36)]
37 #[cfg(any(
38 feature = "postgres",
39 feature = "__sqlite-shared",
40 feature = "mysql",
41 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
42))]
43pub(crate) fn new(s: &'query str) -> Self {
44Self { s }
45 }
46}
4748impl Debugfor StrQueryHelper<'_> {
49fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
50 Debug::fmt(self.s, f)
51 }
52}
5354impl Displayfor StrQueryHelper<'_> {
55fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
56 Display::fmt(&self.s, f)
57 }
58}
5960impl DebugQueryfor StrQueryHelper<'_> {}
6162/// This enum describes possible connection events
63/// that can be handled by an [`Instrumentation`] implementation
64///
65/// Some fields might contain sensitive information, like login
66/// details for the database.
67///
68/// Diesel does not guarantee that future versions will
69/// emit the same events in the same order or timing.
70/// In addition the output of the [`Debug`] and [`Display`]
71/// implementation of the enum itself and any of its fields
72/// is not guarantee to be stable.
73//
74// This type is carefully designed
75// to avoid any potential overhead by
76// taking references for all things
77// and by not performing any additional
78// work until required.
79// In addition it's carefully designed
80// not to be dependent on the actual backend
81// type, as that makes it easier to reuse
82// `Instrumentation` implementations in
83// a different context
84#[derive(#[automatically_derived]
impl<'a> ::core::fmt::Debug for InstrumentationEvent<'a> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
InstrumentationEvent::StartEstablishConnection { url: __self_0 }
=>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"StartEstablishConnection", "url", &__self_0),
InstrumentationEvent::FinishEstablishConnection {
url: __self_0, error: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"FinishEstablishConnection", "url", __self_0, "error",
&__self_1),
InstrumentationEvent::StartQuery { query: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"StartQuery", "query", &__self_0),
InstrumentationEvent::CacheQuery { sql: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"CacheQuery", "sql", &__self_0),
InstrumentationEvent::FinishQuery {
query: __self_0, error: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"FinishQuery", "query", __self_0, "error", &__self_1),
InstrumentationEvent::BeginTransaction { depth: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"BeginTransaction", "depth", &__self_0),
InstrumentationEvent::CommitTransaction { depth: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"CommitTransaction", "depth", &__self_0),
InstrumentationEvent::RollbackTransaction { depth: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"RollbackTransaction", "depth", &__self_0),
}
}
}Debug)]
85#[non_exhaustive]
86pub enum InstrumentationEvent<'a> {
87/// An event emitted by before starting
88 /// establishing a new connection
89#[non_exhaustive]
90StartEstablishConnection {
91/// The database url the connection
92 /// tries to connect to
93 ///
94 /// This might contain sensitive information
95 /// like the database password
96url: &'a str,
97 },
98/// An event emitted after establishing a
99 /// new connection
100#[non_exhaustive]
101FinishEstablishConnection {
102/// The database url the connection
103 /// tries is connected to
104 ///
105 /// This might contain sensitive information
106 /// like the database password
107url: &'a str,
108/// An optional error if the connection failed
109error: Option<&'a crate::result::ConnectionError>,
110 },
111/// An event that is emitted before executing
112 /// a query
113#[non_exhaustive]
114StartQuery {
115/// A opaque representation of the query
116 ///
117 /// This type implements [`Debug`] and [`Display`],
118 /// but should be considered otherwise as opaque.
119 ///
120 /// The exact output of the [`Debug`] and [`Display`]
121 /// implementation is not considered as part of the
122 /// stable API.
123query: &'a dyn DebugQuery,
124 },
125/// An event that is emitted when a query
126 /// is cached in the connection internal
127 /// prepared statement cache
128#[non_exhaustive]
129CacheQuery {
130/// SQL string of the cached query
131sql: &'a str,
132 },
133/// An event that is emitted after executing
134 /// a query
135#[non_exhaustive]
136FinishQuery {
137/// A opaque representation of the query
138 ///
139 /// This type implements [`Debug`] and [`Display`],
140 /// but should be considered otherwise as opaque.
141 ///
142 /// The exact output of the [`Debug`] and [`Display`]
143 /// implementation is not considered as part of the
144 /// stable API.
145query: &'a dyn DebugQuery,
146/// An optional error if the connection failed
147error: Option<&'a crate::result::Error>,
148 },
149/// An event that is emitted while
150 /// starting a new transaction
151#[non_exhaustive]
152BeginTransaction {
153/// Transaction level of the newly started
154 /// transaction
155depth: NonZeroU32,
156 },
157/// An event that is emitted while
158 /// committing a transaction
159#[non_exhaustive]
160CommitTransaction {
161/// Transaction level of the to be committed
162 /// transaction
163depth: NonZeroU32,
164 },
165/// An event that is emitted while
166 /// rolling back a transaction
167#[non_exhaustive]
168RollbackTransaction {
169/// Transaction level of the to be rolled
170 /// back transaction
171depth: NonZeroU32,
172 },
173}
174175// these constructors exist to
176// keep `#[non_exhaustive]` on all the variants
177// and to gate the constructors on the unstable feature
178#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
179impl<'a> InstrumentationEvent<'a> {
180/// Create a new `InstrumentationEvent::StartEstablishConnection` event
181#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
182pub fn start_establish_connection(url: &'a str) -> Self {
183Self::StartEstablishConnection { url }
184 }
185186/// Create a new `InstrumentationEvent::FinishEstablishConnection` event
187#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
188pub fn finish_establish_connection(
189 url: &'a str,
190 error: Option<&'a crate::result::ConnectionError>,
191 ) -> Self {
192Self::FinishEstablishConnection { url, error }
193 }
194195/// Create a new `InstrumentationEvent::StartQuery` event
196#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
197pub fn start_query(query: &'a dyn DebugQuery) -> Self {
198Self::StartQuery { query }
199 }
200201/// Create a new `InstrumentationEvent::CacheQuery` event
202#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
203pub fn cache_query(sql: &'a str) -> Self {
204Self::CacheQuery { sql }
205 }
206207/// Create a new `InstrumentationEvent::FinishQuery` event
208#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
209pub fn finish_query(
210 query: &'a dyn DebugQuery,
211 error: Option<&'a crate::result::Error>,
212 ) -> Self {
213Self::FinishQuery { query, error }
214 }
215216/// Create a new `InstrumentationEvent::BeginTransaction` event
217#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
218pub fn begin_transaction(depth: NonZeroU32) -> Self {
219Self::BeginTransaction { depth }
220 }
221222/// Create a new `InstrumentationEvent::RollbackTransaction` event
223#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
224pub fn rollback_transaction(depth: NonZeroU32) -> Self {
225Self::RollbackTransaction { depth }
226 }
227228/// Create a new `InstrumentationEvent::CommitTransaction` event
229#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
230pub fn commit_transaction(depth: NonZeroU32) -> Self {
231Self::CommitTransaction { depth }
232 }
233}
234235/// A type that provides an connection `Instrumentation`
236///
237/// This trait is the basic building block for logging or
238/// otherwise instrumenting diesel connection types. It
239/// acts as callback that receives information about certain
240/// important connection states
241///
242/// For simple usages this trait is implemented for closures
243/// accepting a [`InstrumentationEvent`] as argument.
244///
245/// More complex usages and integrations with frameworks like
246/// `tracing` and `log` are supposed to be part of their own
247/// crates.
248pub trait Instrumentation: Downcast + Send + 'static {
249/// The function that is invoked for each event
250fn on_connection_event(&mut self, event: InstrumentationEvent<'_>);
251}
252impl dyn Instrumentation<> {
/// Returns true if the trait object wraps an object of type `__T`.
#[inline]
pub fn is<__T: Instrumentation<>>(&self) -> bool {
::downcast_rs::Downcast::as_any(self).is::<__T>()
}
/// Returns a boxed object from a boxed trait object if the underlying object is of type
/// `__T`. Returns the original boxed trait if it isn't.
#[inline]
pub fn downcast<__T: Instrumentation<>>(self:
::downcast_rs::__alloc::boxed::Box<Self>)
->
::downcast_rs::__std::result::Result<::downcast_rs::__alloc::boxed::Box<__T>,
::downcast_rs::__alloc::boxed::Box<Self>> {
if self.is::<__T>() {
Ok(::downcast_rs::Downcast::into_any(self).downcast::<__T>().unwrap())
} else { Err(self) }
}
/// Returns an `Rc`-ed object from an `Rc`-ed trait object if the underlying object is of
/// type `__T`. Returns the original `Rc`-ed trait if it isn't.
#[inline]
pub fn downcast_rc<__T: Instrumentation<>>(self:
::downcast_rs::__alloc::rc::Rc<Self>)
->
::downcast_rs::__std::result::Result<::downcast_rs::__alloc::rc::Rc<__T>,
::downcast_rs::__alloc::rc::Rc<Self>> {
if self.is::<__T>() {
Ok(::downcast_rs::Downcast::into_any_rc(self).downcast::<__T>().unwrap())
} else { Err(self) }
}
/// Returns a reference to the object within the trait object if it is of type `__T`, or
/// `None` if it isn't.
#[inline]
pub fn downcast_ref<__T: Instrumentation<>>(&self)
-> ::downcast_rs::__std::option::Option<&__T> {
::downcast_rs::Downcast::as_any(self).downcast_ref::<__T>()
}
/// Returns a mutable reference to the object within the trait object if it is of type
/// `__T`, or `None` if it isn't.
#[inline]
pub fn downcast_mut<__T: Instrumentation<>>(&mut self)
-> ::downcast_rs::__std::option::Option<&mut __T> {
::downcast_rs::Downcast::as_any_mut(self).downcast_mut::<__T>()
}
}downcast_rs::impl_downcast!(Instrumentation);
253254/// Get an instance of the default [`Instrumentation`]
255///
256/// This function is mostly useful for crates implementing
257/// their own connection types
258pub fn get_default_instrumentation() -> Option<Box<dyn Instrumentation>> {
259#[cfg(feature = "std")]
260match GLOBAL_INSTRUMENTATION.read() {
261Ok(f) => (*f)(),
262Err(_) => None,
263 }
264#[cfg(not(feature = "std"))]
265None
266}
267268/// Set a custom constructor for the default [`Instrumentation`]
269/// used by new connections
270///
271/// ```rust
272/// use diesel::connection::{set_default_instrumentation, Instrumentation, InstrumentationEvent};
273///
274/// // a simple logger that prints all events to stdout
275/// fn simple_logger() -> Option<Box<dyn Instrumentation>> {
276/// // we need the explicit argument type there due
277/// // to bugs in rustc
278/// Some(Box::new(|event: InstrumentationEvent<'_>| {
279/// println!("{event:?}")
280/// }))
281/// }
282///
283/// set_default_instrumentation(simple_logger);
284/// ```
285#[cfg(feature = "std")]
286pub fn set_default_instrumentation(
287 default: fn() -> Option<Box<dyn Instrumentation>>,
288) -> crate::QueryResult<()> {
289match GLOBAL_INSTRUMENTATION.write() {
290Ok(mut l) => {
291*l = default;
292Ok(())
293 }
294Err(e) => Err(crate::result::Error::DatabaseError(
295crate::result::DatabaseErrorKind::Unknown,
296Box::new(e.to_string()),
297 )),
298 }
299}
300301impl<F> Instrumentationfor F
302where
303F: FnMut(InstrumentationEvent<'_>) + Send + 'static,
304{
305fn on_connection_event(&mut self, event: InstrumentationEvent<'_>) {
306 (self)(event)
307 }
308}
309310impl Instrumentationfor Box<dyn Instrumentation> {
311fn on_connection_event(&mut self, event: InstrumentationEvent<'_>) {
312self.deref_mut().on_connection_event(event)
313 }
314}
315316impl<T> Instrumentationfor Option<T>
317where
318T: Instrumentation,
319{
320fn on_connection_event(&mut self, event: InstrumentationEvent<'_>) {
321if let Some(i) = self {
322i.on_connection_event(event)
323 }
324 }
325}
326327#[doc = " An optional dyn instrumentation."]
#[doc = ""]
#[doc =
" For ease of use, this type implements [`Deref`] and [`DerefMut`] to `&dyn Instrumentation`,"]
#[doc =
" falling back to a no-op implementation if no instrumentation is set."]
#[doc = ""]
#[doc =
" The DynInstrumentation type is useful because without it we actually did tend to return"]
#[doc =
" (accidentally) `&mut Option<Box> as &mut dyn Instrumentation` from `connection.instrumentation()`,"]
#[doc =
" so downcasting would have to be done in these two steps by the user, which is counter-intuitive."]
#[non_exhaustive]
pub struct DynInstrumentation {
#[doc = " zst"]
no_instrumentation: NoInstrumentation,
inner: Option<Box<dyn Instrumentation>>,
}#[diesel_derives::__diesel_public_if(
328 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
329)]330/// An optional dyn instrumentation.
331///
332/// For ease of use, this type implements [`Deref`] and [`DerefMut`] to `&dyn Instrumentation`,
333/// falling back to a no-op implementation if no instrumentation is set.
334///
335/// The DynInstrumentation type is useful because without it we actually did tend to return
336/// (accidentally) `&mut Option<Box> as &mut dyn Instrumentation` from `connection.instrumentation()`,
337/// so downcasting would have to be done in these two steps by the user, which is counter-intuitive.
338pub(crate) struct DynInstrumentation {
339/// zst
340no_instrumentation: NoInstrumentation,
341 inner: Option<Box<dyn Instrumentation>>,
342}
343344impl Dereffor DynInstrumentation {
345type Target = dyn Instrumentation;
346347fn deref(&self) -> &Self::Target {
348self.inner.as_deref().unwrap_or(&self.no_instrumentation)
349 }
350}
351352impl DerefMutfor DynInstrumentation {
353fn deref_mut(&mut self) -> &mut Self::Target {
354self.inner
355 .as_deref_mut()
356 .unwrap_or(&mut self.no_instrumentation)
357 }
358}
359360impl DynInstrumentation {
361/// Create a instance of the default instrumentation provider
362#[diesel_derives::__diesel_public_if(
363 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
364)]
365 #[cfg(any(
366 feature = "postgres",
367 feature = "__sqlite-shared",
368 feature = "mysql",
369 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
370))]
371pub(crate) fn default_instrumentation() -> Self {
372Self {
373 inner: get_default_instrumentation(),
374 no_instrumentation: NoInstrumentation,
375 }
376 }
377378/// Create a noop instrumentation provider instance
379#[diesel_derives::__diesel_public_if(
380 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
381)]
382 #[cfg(any(
383 feature = "postgres",
384 feature = "__sqlite-shared",
385 feature = "mysql",
386 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
387))]
388pub(crate) fn none() -> Self {
389Self {
390 inner: None,
391 no_instrumentation: NoInstrumentation,
392 }
393 }
394395/// register an event with the given instrumentation implementation
396#[diesel_derives::__diesel_public_if(
397 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
398)]
399 #[cfg(any(
400 feature = "postgres",
401 feature = "__sqlite-shared",
402 feature = "mysql",
403 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
404))]
405pub(crate) fn on_connection_event(&mut self, event: InstrumentationEvent<'_>) {
406// This implementation is not necessary to be able to call this method on this object
407 // because of the already existing Deref impl.
408 // However it allows avoiding the dynamic dispatch to the stub value
409if let Some(inner) = self.inner.as_deref_mut() {
410inner.on_connection_event(event)
411 }
412 }
413}
414415impl<I: Instrumentation> From<I> for DynInstrumentation {
416fn from(instrumentation: I) -> Self {
417Self {
418 inner: Some(unpack_instrumentation(Box::new(instrumentation))),
419 no_instrumentation: NoInstrumentation,
420 }
421 }
422}
423424struct NoInstrumentation;
425426impl Instrumentationfor NoInstrumentation {
427fn on_connection_event(&mut self, _: InstrumentationEvent<'_>) {}
428}
429430/// Unwrap unnecessary boxing levels
431fn unpack_instrumentation(
432mut instrumentation: Box<dyn Instrumentation>,
433) -> Box<dyn Instrumentation> {
434loop {
435match instrumentation.downcast::<Box<dyn Instrumentation>>() {
436Ok(extra_boxed_instrumentation) => instrumentation = *extra_boxed_instrumentation,
437Err(not_extra_boxed_instrumentation) => {
438break not_extra_boxed_instrumentation;
439 }
440 }
441 }
442}