1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
//! A Logger wrapper to integrate the Sentry SDK on a Rocket Server easily
//!
//! Offers a set of functions which helps to log simple messages to sentry,
//! configure users, and set up a fairing on a Rocket server

#![feature(proc_macro_hygiene, decl_macro)]

extern crate rocket;
extern crate sentry;

pub mod fairing;
mod steps;

use fairing::LoggerFairing;
use rocket::fairing::Fairing;
use sentry::{Breadcrumb, ClientOptions};
/// Sentry Log level & User config
pub use sentry::{ClientInitGuard as Guard, Level as LogLevel, User};
pub use steps::{Step, StepType};

/// Initialize a sentry client instance with the recommended sentry configuration.
/// Reads the *SENTRY_DNS* variable from the environment to start the client
///
/// Returns a Sentry ClientInitGuard which will stop the logging service when dropped
///
/// # Panics!
///
/// Panics if the sentry instance is not enabled after the init is done.
/// That can happens due to an invalid dns.
///
///```rust
/// fn main() {
///     logger::init();
/// }
///```
pub fn init() -> Guard {
    let dsn = std::env::var("SENTRY_DSN").expect("SENTRY_DSN must be set");
    let options = ClientOptions {
        send_default_pii: true,
        attach_stacktrace: true,
        release: sentry::release_name!(),
        ..Default::default()
    };
    let guard = sentry::init((dsn, options));
    if !guard.is_enabled() {
        panic!("Could not initialize sentry");
    }
    guard
}

/// Logs a message to sentry.
/// Use the *LogLevel* enum to set up the desired logging level.
/// Every step tracked previous to the log on the same execution thread
/// will be sent along with the message.
///
///```rust
/// fn main() {
///     logger::log("This is a mock message, Hello World!", LogLevel::Info);
/// }
///```
pub fn log(message: &str, level: LogLevel) {
    let _uuid = sentry::capture_message(message, level);
}

/// Tracks an step to be sent along with the next logged message or event.
///
/// ```rust
/// let step = Step {
///   ty: StepType::Error,
///   title: "Bad request".into(),
///   message: "Mike made a bad request".into(),
///   level: LogLevel::Info,
///   data: None,
/// };
///
/// logger::track_step(step);
/// ```
pub fn track_step(step: Step) {
    let breadcrumb: Breadcrumb = step.into();
    sentry::add_breadcrumb(breadcrumb);
}

/// Allows you to set info about the user related with the current scope.
///
/// ```rust
/// let user = User {
///   id: Some("aslfnsvn-dsvjnfv-ffjfvkfjd"),
///   email: Some("jaster@mail.com"),
///   username: Some("Jaster"),
///   ..Default::default()
/// };
///
/// logger::set_user(user);
/// ```
pub fn set_user(user: User) {
    sentry::configure_scope(|scope| {
        scope.set_user(Some(user));
    })
}

/// Returns an instance of [`LoggerFairing`] to be attached on a rocket instance
///
/// ```rust
/// fn main() {
///    rocket::ignite()
///    .attach(logger::fairing());
/// }
/// ```
pub fn fairing() -> impl Fairing {
    LoggerFairing
}