Skip to content

Commit e0a97fe

Browse files
committed
format log lines. LogItem::new.
1 parent 0ab3e5d commit e0a97fe

File tree

6 files changed

+137
-163
lines changed

6 files changed

+137
-163
lines changed

common/src/log.rs

Lines changed: 103 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1+
use std::fmt::Write;
2+
13
use chrono::{DateTime, Utc};
24
#[cfg(feature = "display")]
5+
use crossterm::style::StyledContent;
6+
#[cfg(feature = "display")]
37
use crossterm::style::Stylize;
48
use serde::{Deserialize, Serialize};
59
use strum::EnumString;
6-
use tracing::{field::Visit, span, warn, Metadata, Subscriber};
10+
use tracing::{field::Visit, span, warn, Event, Level, Metadata, Subscriber};
711
use tracing_subscriber::Layer;
812
#[cfg(feature = "openapi")]
913
use utoipa::ToSchema;
1014
use uuid::Uuid;
1115

16+
use crate::tracing::JsonVisitor;
17+
1218
/// Used to determine settings based on which backend crate does what
1319
#[derive(Clone, Debug, EnumString, Eq, PartialEq, Deserialize, Serialize)]
1420
#[cfg_attr(feature = "display", derive(strum::Display))]
@@ -52,21 +58,85 @@ pub struct LogItem {
5258
pub line: String,
5359
}
5460

61+
impl LogItem {
62+
pub fn new(id: Uuid, internal_origin: Backend, line: String) -> Self {
63+
Self {
64+
id,
65+
internal_origin,
66+
timestamp: Utc::now(),
67+
line,
68+
}
69+
}
70+
}
71+
5572
#[cfg(feature = "display")]
5673
impl std::fmt::Display for LogItem {
5774
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5875
let datetime: chrono::DateTime<chrono::Local> = DateTime::from(self.timestamp);
5976

6077
write!(
6178
f,
62-
"{} [{}] {}",
79+
"{} {} {}",
6380
datetime.to_rfc3339().dim(),
64-
self.internal_origin,
81+
format!("[{}]", self.internal_origin).grey(),
6582
self.line,
6683
)
6784
}
6885
}
6986

87+
#[cfg(feature = "display")]
88+
pub trait ColoredLevel {
89+
fn colored(&self) -> StyledContent<&str>;
90+
}
91+
92+
#[cfg(feature = "display")]
93+
impl ColoredLevel for tracing::Level {
94+
fn colored(&self) -> StyledContent<&str> {
95+
match *self {
96+
Level::TRACE => "TRACE".magenta(),
97+
Level::DEBUG => "DEBUG".blue(),
98+
Level::INFO => " INFO".green(),
99+
Level::WARN => " WARN".yellow(),
100+
Level::ERROR => "ERROR".red(),
101+
}
102+
}
103+
}
104+
105+
#[cfg(feature = "display")]
106+
pub fn format_event(event: &Event<'_>) -> String {
107+
let metadata = event.metadata();
108+
let mut visitor = JsonVisitor::default();
109+
event.record(&mut visitor);
110+
111+
let mut message = String::new();
112+
113+
let target = visitor
114+
.target
115+
.unwrap_or_else(|| metadata.target().to_string());
116+
117+
if !target.is_empty() {
118+
let t = format!("{target}: ").dim();
119+
write!(message, "{t}").unwrap();
120+
}
121+
122+
let mut simple = None;
123+
let mut extra = vec![];
124+
for (key, value) in visitor.fields.iter() {
125+
match key.as_str() {
126+
"message" => simple = value.as_str(),
127+
_ => extra.push(format!("{key}={value}")),
128+
}
129+
}
130+
if !extra.is_empty() {
131+
write!(message, "{{{}}} ", extra.join(" ")).unwrap();
132+
}
133+
if let Some(msg) = simple {
134+
write!(message, "{msg}").unwrap();
135+
}
136+
137+
format!("{} {}", metadata.level().colored(), message)
138+
}
139+
70140
/// Records logs for the deployment progress
71141
pub trait LogRecorder: Clone + Send + 'static {
72142
fn record(&self, log: LogItem);
@@ -95,17 +165,16 @@ where
95165
return;
96166
};
97167

98-
// Find the outermost scope with the scope details containing the current state
168+
// Find the outermost scope with the scope details containing the current deployment id
99169
for span in scope.from_root() {
100170
let extensions = span.extensions();
101171

102172
if let Some(details) = extensions.get::<ScopeDetails>() {
103-
self.recorder.record(LogItem {
104-
id: details.id,
105-
internal_origin: self.internal_service.clone(),
106-
timestamp: Utc::now(),
107-
line: "Test".into(),
108-
});
173+
self.recorder.record(LogItem::new(
174+
details.deployment_id,
175+
self.internal_service.clone(),
176+
format_event(event),
177+
));
109178
break;
110179
}
111180
}
@@ -124,39 +193,46 @@ where
124193
attrs.record(&mut visitor);
125194
let details = visitor.details;
126195

127-
if details.id.is_nil() {
128-
warn!("scope details does not have a valid id");
196+
if details.deployment_id.is_nil() {
197+
warn!("scope details does not have a valid deployment_id");
129198
return;
130199
}
131200

132201
// Safe to unwrap since this is the `on_new_span` method
133202
let span = ctx.span(id).unwrap();
134203
let mut extensions = span.extensions_mut();
135204

136-
self.recorder.record(LogItem {
137-
id: details.id,
138-
internal_origin: self.internal_service.clone(),
139-
timestamp: Utc::now(),
140-
line: "Test".into(),
141-
});
205+
let metadata = attrs.metadata();
206+
207+
let message = format!(
208+
"{} Entering span {}",
209+
metadata.level().colored(),
210+
metadata.name().blue(),
211+
);
212+
213+
self.recorder.record(LogItem::new(
214+
details.deployment_id,
215+
self.internal_service.clone(),
216+
message,
217+
));
142218

143219
extensions.insert::<ScopeDetails>(details);
144220
}
145221
}
146222

147223
#[derive(Debug, Default)]
148224
struct ScopeDetails {
149-
id: Uuid,
225+
deployment_id: Uuid,
150226
}
151-
/// To extract `id` field for scopes that have it
227+
/// To extract `deployment_id` field for scopes that have it
152228
#[derive(Default)]
153229
struct DeploymentIdVisitor {
154230
details: ScopeDetails,
155231
}
156232

157233
impl DeploymentIdVisitor {
158234
/// Field containing the deployment identifier
159-
const ID_IDENT: &'static str = "id";
235+
const ID_IDENT: &'static str = "deployment_id";
160236

161237
fn is_valid(metadata: &Metadata) -> bool {
162238
metadata.is_span() && metadata.fields().field(Self::ID_IDENT).is_some()
@@ -166,7 +242,7 @@ impl DeploymentIdVisitor {
166242
impl Visit for DeploymentIdVisitor {
167243
fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
168244
if field.name() == Self::ID_IDENT {
169-
self.details.id = Uuid::try_parse(&format!("{value:?}")).unwrap_or_default();
245+
self.details.deployment_id = Uuid::try_parse(&format!("{value:?}")).unwrap_or_default();
170246
}
171247
}
172248
}
@@ -186,12 +262,11 @@ mod tests {
186262

187263
#[test]
188264
fn test_timezone_formatting() {
189-
let item = LogItem {
190-
id: Uuid::new_v4(),
191-
internal_origin: Backend::Deployer,
192-
timestamp: Utc::now(),
193-
line: r#"{"message": "Building"}"#.to_owned(),
194-
};
265+
let item = LogItem::new(
266+
Uuid::new_v4(),
267+
Backend::Deployer,
268+
r#"{"message": "Building"}"#.to_owned(),
269+
);
195270

196271
with_tz("CEST", || {
197272
let cest_dt = item.timestamp.with_timezone(&chrono::Local).to_rfc3339();

deployer/src/deployment/queue.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,21 +190,20 @@ impl Queued {
190190
info!("Building deployment");
191191

192192
let (tx, rx): (crossbeam_channel::Sender<Message>, _) = crossbeam_channel::bounded(0);
193-
let id = self.id;
193+
194194
tokio::task::spawn_blocking(move || {
195195
while let Ok(message) = rx.recv() {
196196
trace!(?message, "received cargo message");
197197
// TODO: change these to `info!(...)` as [valuable] support increases.
198198
// Currently it is not possible to turn these serde `message`s into a `valuable`, but once it is the passing down of `log_recorder` should be removed.
199-
let log = LogItem {
200-
id: self.id,
201-
internal_origin: shuttle_common::log::Backend::Deployer, // will change to Builder
202-
timestamp: Utc::now(),
203-
line: match message {
199+
let log = LogItem::new(
200+
self.id,
201+
shuttle_common::log::Backend::Deployer, // will change to Builder
202+
match message {
204203
Message::TextLine(line) => line,
205204
message => serde_json::to_string(&message).unwrap(),
206205
},
207-
};
206+
);
208207
log_recorder.record(log);
209208
}
210209
});
@@ -243,7 +242,7 @@ impl Queued {
243242
let is_next = built_service.is_wasm;
244243

245244
deployment_updater
246-
.set_is_next(&id, is_next)
245+
.set_is_next(&self.id, is_next)
247246
.await
248247
.map_err(|e| Error::Build(Box::new(e)))?;
249248

deployer/src/deployment/state_change_layer.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use tracing_subscriber::Layer;
2525
use uuid::Uuid;
2626

2727
use shuttle_common::{
28-
log::{Backend, LogRecorder},
28+
log::{Backend, ColoredLevel, LogRecorder},
2929
LogItem,
3030
};
3131

@@ -74,12 +74,15 @@ where
7474
state: visitor.state,
7575
});
7676
// To logger
77-
self.log_recorder.record(LogItem {
78-
id: visitor.id,
79-
internal_origin: Backend::Deployer,
80-
timestamp: Utc::now(),
81-
line: format!(" INFO Entering {:?} state", visitor.state),
82-
});
77+
self.log_recorder.record(LogItem::new(
78+
visitor.id,
79+
Backend::Deployer,
80+
format!(
81+
"{} {}",
82+
tracing::Level::INFO.colored(),
83+
format!("Entering {} state", visitor.state), // make blue?
84+
),
85+
));
8386
}
8487
}
8588

deployer/src/persistence/log.rs

Lines changed: 0 additions & 111 deletions
This file was deleted.

0 commit comments

Comments
 (0)