Skip to content

Commit b4df1bf

Browse files
authored
feat: Added JSON logging (#32)
1 parent 8b0f006 commit b4df1bf

File tree

6 files changed

+108
-32
lines changed

6 files changed

+108
-32
lines changed

Cargo.lock

+9-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+6-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ with_ssl = ["semaphore-server/with_ssl"]
1515

1616
[profile.release]
1717
lto = true
18+
debug = true
1819

1920
[dependencies]
2021
clap = { version = "2.31.2", default-features = false, features = ["wrap_help"] }
@@ -24,12 +25,16 @@ tokio-core = "0.1.17"
2425
futures = "0.1.21"
2526
parking_lot = "0.5.5"
2627
ctrlc = { version = "3.1.1", features = ["termination"] }
27-
log = "0.4.2"
28+
log = { version = "0.4.2", features = ["serde"] }
2829
sentry = "0.5.4"
2930
dialoguer = "0.1.0"
3031
uuid = "0.6.5"
3132
console = "0.6.1"
3233
env_logger = "0.5.10"
34+
chrono = "0.4.3"
35+
serde_derive = "1.0.66"
36+
serde = "1.0.66"
37+
serde_json = "1.0.20"
3338

3439
[dependencies.semaphore-aorta]
3540
path = "aorta"

config/src/types.rs

+22
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,20 @@ pub struct MinimalConfig {
124124
pub relay: Relay,
125125
}
126126

127+
/// Controls the log format
128+
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
129+
#[serde(rename_all = "lowercase")]
130+
pub enum LogFormat {
131+
/// Auto detect (pretty for tty, simplified for other)
132+
Auto,
133+
/// With colors
134+
Pretty,
135+
/// Simplified log output
136+
Simplified,
137+
/// Dump out JSON lines
138+
Json,
139+
}
140+
127141
/// Controls the logging system.
128142
#[derive(Serialize, Deserialize, Debug)]
129143
#[serde(default)]
@@ -132,6 +146,8 @@ struct Logging {
132146
level: log::LevelFilter,
133147
/// If set to true this emits log messages for failed event payloads.
134148
log_failed_payloads: bool,
149+
/// Controls the log format.
150+
format: LogFormat,
135151
/// When set to true, backtraces are forced on.
136152
enable_backtraces: bool,
137153
}
@@ -194,6 +210,7 @@ impl Default for Logging {
194210
Logging {
195211
level: log::LevelFilter::Info,
196212
log_failed_payloads: false,
213+
format: LogFormat::Auto,
197214
enable_backtraces: true,
198215
}
199216
}
@@ -514,6 +531,11 @@ impl Config {
514531
self.values.logging.log_failed_payloads
515532
}
516533

534+
/// Which log format should be used?
535+
pub fn log_format(&self) -> LogFormat {
536+
self.values.logging.format
537+
}
538+
517539
/// Returns the socket addresses for statsd.
518540
///
519541
/// If stats is disabled an empty vector is returned.

server/src/extractors.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,25 @@ impl<T: FromRequest<ServiceState> + 'static> FromRequest<ServiceState> for Proje
116116

117117
req.extensions_mut().insert(auth.clone());
118118

119-
match req.match_info()
119+
let project_id = match req.match_info()
120120
.get("project")
121121
.unwrap_or_default()
122122
.parse::<ProjectId>()
123123
.map_err(BadProjectRequest::BadProject)
124124
{
125-
Ok(project_id) => req.extensions_mut().insert(project_id),
125+
Ok(project_id) => project_id,
126126
Err(err) => return Box::new(future::err(err.into())),
127127
};
128128

129+
sentry::configure_scope(|scope| {
130+
scope.set_user(Some(sentry::User {
131+
id: Some(project_id.to_string()),
132+
..Default::default()
133+
}));
134+
});
135+
136+
req.extensions_mut().insert(project_id);
137+
129138
Box::new(
130139
T::from_request(&req, cfg)
131140
.into()

src/main.rs

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ extern crate parking_lot;
1313
extern crate pretty_env_logger;
1414
#[macro_use]
1515
extern crate sentry;
16+
extern crate serde;
17+
#[macro_use]
18+
extern crate serde_derive;
19+
extern crate chrono;
20+
extern crate serde_json;
1621
extern crate uuid;
1722

1823
extern crate semaphore_common;

src/setup.rs

+55-18
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
use std::env;
2+
use std::io;
23
use std::io::Write;
34

5+
use chrono::{DateTime, Utc};
46
use console;
57
use env_logger;
68
use failure::Error;
7-
use log::LevelFilter;
9+
use log::{Level, LevelFilter};
810
use pretty_env_logger;
911
use sentry;
12+
use serde_json;
1013

1114
use semaphore_common::metrics;
12-
use semaphore_config::Config;
15+
use semaphore_config::{Config, LogFormat};
1316

1417
/// Print spawn infos to the log.
1518
pub fn dump_spawn_infos(config: &Config) {
@@ -79,22 +82,56 @@ pub fn init_logging(config: &Config) {
7982
}
8083

8184
let mut log_builder = {
82-
if console::user_attended() {
83-
pretty_env_logger::formatted_builder().unwrap()
84-
} else {
85-
let mut builder = env_logger::Builder::new();
86-
builder.format(|buf, record| {
87-
let ts = buf.timestamp();
88-
writeln!(
89-
buf,
90-
"{} [{}] {}: {}",
91-
ts,
92-
record.module_path().unwrap_or("<unknown>"),
93-
record.level(),
94-
record.args()
95-
)
96-
});
97-
builder
85+
match (config.log_format(), console::user_attended()) {
86+
(LogFormat::Auto, true) | (LogFormat::Pretty, _) => {
87+
pretty_env_logger::formatted_builder().unwrap()
88+
}
89+
(LogFormat::Auto, false) | (LogFormat::Simplified, _) => {
90+
let mut builder = env_logger::Builder::new();
91+
builder.format(|buf, record| {
92+
let ts = buf.timestamp();
93+
writeln!(
94+
buf,
95+
"{} [{}] {}: {}",
96+
ts,
97+
record.module_path().unwrap_or("<unknown>"),
98+
record.level(),
99+
record.args()
100+
)
101+
});
102+
builder
103+
}
104+
(LogFormat::Json, _) => {
105+
#[derive(Serialize, Deserialize, Debug)]
106+
struct LogRecord<'a> {
107+
timestamp: DateTime<Utc>,
108+
level: Level,
109+
logger: &'a str,
110+
message: String,
111+
module_path: Option<&'a str>,
112+
filename: Option<&'a str>,
113+
lineno: Option<u32>,
114+
}
115+
116+
let mut builder = env_logger::Builder::new();
117+
builder.format(|mut buf, record| -> io::Result<()> {
118+
serde_json::to_writer(
119+
&mut buf,
120+
&LogRecord {
121+
timestamp: Utc::now(),
122+
level: record.level(),
123+
logger: record.target(),
124+
message: record.args().to_string(),
125+
module_path: record.module_path(),
126+
filename: record.file(),
127+
lineno: record.line(),
128+
},
129+
).map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
130+
buf.write(b"\n")?;
131+
Ok(())
132+
});
133+
builder
134+
}
98135
}
99136
};
100137

0 commit comments

Comments
 (0)