Skip to content

Commit 17a874b

Browse files
committed
[add] updated log improvements, new examples, and new documentation.
1 parent ba0a1fb commit 17a874b

File tree

7 files changed

+511
-181
lines changed

7 files changed

+511
-181
lines changed

crates/lambda-rs-logging/README.md

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,87 @@
22
![lambda-rs](https://img.shields.io/crates/d/lambda-rs-logging)
33
![lambda-rs](https://img.shields.io/crates/v/lambda-rs-logging)
44

5-
A simple logger implementation for lamba-rs crates. Inspired by
6-
python's [logging](https://docs.python.org/3/library/logging.html) module.
5+
Simple, lightweight logging for lambda-rs crates. Inspired by Python’s
6+
[logging](https://docs.python.org/3/library/logging.html) module.
77

88

9-
# Installation
10-
First, add the following to your `Cargo.toml`:
9+
## Installation
10+
Add to your `Cargo.toml`:
1111
```toml
1212
[dependencies]
13+
# Option A: use the crate name in code as `lambda_rs_logging`
1314
lambda-rs-logging = "2023.1.30"
15+
16+
# Option B: rename dependency so you can write `use logging;`
17+
# logging = { package = "lambda-rs-logging", version = "2023.1.30" }
1418
```
1519

16-
or run this command from your project directory:
20+
Or from your project directory:
1721
```bash
1822
cargo add lambda-rs-logging
1923
```
2024

21-
# Getting started
22-
## Using the global logger
25+
Then in code, either import with the default name:
26+
```rust
27+
use lambda_rs_logging as logging;
28+
```
29+
or, if you used the rename in Cargo.toml (Option B), simply:
30+
```rust
31+
use logging; // renamed in Cargo.toml
32+
```
33+
34+
## Getting Started
35+
### Global logger via macros
2336
```rust
24-
use logging;
37+
use lambda_rs_logging as logging;
2538

2639
fn main() {
27-
logging::trace!("Hello world");
28-
logging::debug!("Hello world");
29-
logging::info!("Hello world");
30-
logging::warn!("Hello world");
31-
logging::error!("Hello world");
32-
logging::fatal!("Hello world");
40+
logging::trace!("trace {}", 1);
41+
logging::debug!("debug {}", 2);
42+
logging::info!("info {}", 3);
43+
logging::warn!("warn {}", 4);
44+
logging::error!("error {}", 5);
45+
logging::fatal!("fatal {}", 6); // note: does not exit
3346
}
3447
```
3548

36-
## Using an instance of the logger
49+
### Custom logger instance
3750
```rust
38-
use logging::Logger;
51+
use lambda_rs_logging as logging;
3952

4053
fn main() {
41-
let logger = Logger::new("my-logger");
42-
logger.trace("Hello world");
43-
logger.debug("Hello world");
44-
logger.info("Hello world");
45-
logger.warn("Hello world");
46-
logger.error("Hello world");
47-
logger.fatal("Hello world");
54+
let logger = logging::Logger::new(logging::LogLevel::INFO, "my-app");
55+
logger.add_handler(Box::new(logging::handler::ConsoleHandler::new("my-app")));
56+
57+
logger.info("Hello world".to_string());
58+
logger.warn("Be careful".to_string());
4859
}
4960
```
61+
62+
### Initialize a custom global
63+
```rust
64+
use lambda_rs_logging as logging;
65+
66+
fn main() {
67+
let logger = logging::Logger::new(logging::LogLevel::DEBUG, "app");
68+
logger.add_handler(Box::new(logging::handler::ConsoleHandler::new("app")));
69+
70+
// Set the global logger before any macros are used
71+
logging::Logger::init(logger).expect("global logger can only be initialized once");
72+
73+
logging::debug!("from global");
74+
}
75+
```
76+
77+
## Notes
78+
- Thread-safe global with `OnceLock<Arc<Logger>>`.
79+
- Handlers are `Send + Sync` and receive a `Record` internally (phase 1 refactor).
80+
- `fatal!` logs at FATAL level but does not exit the process. Prefer explicit exits in your app logic.
81+
82+
## Examples
83+
This crate ships with examples. From the repository root:
84+
```bash
85+
cargo run -p lambda-rs-logging --example 01_global_macros
86+
cargo run -p lambda-rs-logging --example 02_custom_logger
87+
cargo run -p lambda-rs-logging --example 03_global_init
88+
```
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
logging::trace!("trace example");
3+
logging::debug!("debug example: {}", 42);
4+
logging::info!("info example");
5+
logging::warn!("warn example");
6+
logging::error!("error example");
7+
logging::fatal!("fatal example (no exit)");
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
let logger = logging::Logger::new(logging::LogLevel::DEBUG, "custom");
3+
logger.add_handler(Box::new(logging::handler::ConsoleHandler::new("custom")));
4+
5+
logger.trace("this will be filtered unless level <= TRACE".to_string());
6+
logger.debug("debug from custom logger".to_string());
7+
logger.info("info from custom logger".to_string());
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn main() {
2+
let logger = logging::Logger::new(logging::LogLevel::INFO, "app");
3+
logger.add_handler(Box::new(logging::handler::ConsoleHandler::new("app")));
4+
5+
logging::Logger::init(logger)
6+
.expect("global logger can only be initialized once");
7+
8+
logging::info!("hello from initialized global");
9+
}
Lines changed: 34 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,52 @@
11
//! Log handling implementations for the logger.
22
33
use std::{
4-
fmt::Debug,
54
fs::OpenOptions,
65
io::Write,
6+
sync::Mutex,
77
time::SystemTime,
88
};
99

10-
use crate::LogLevel;
10+
use crate::{
11+
LogLevel,
12+
Record,
13+
};
1114

1215
/// Pluggable sink for log records emitted by the `Logger`.
13-
///
14-
/// Implementors decide how to format and where to deliver messages for each
15-
/// severity level.
16-
pub trait Handler {
17-
fn trace(&mut self, message: String);
18-
fn debug(&mut self, message: String);
19-
fn info(&mut self, message: String);
20-
fn warn(&mut self, message: String);
21-
fn error(&mut self, message: String);
22-
fn fatal(&mut self, message: String);
16+
/// Implementors decide how to format and where to deliver messages.
17+
pub trait Handler: Send + Sync {
18+
fn log(&self, record: &Record);
2319
}
2420

2521
/// A handler that logs to a file.
26-
27-
#[derive(Debug, Clone, PartialEq, PartialOrd)]
22+
#[derive(Debug)]
2823
pub struct FileHandler {
2924
file: String,
30-
log_buffer: Vec<String>,
25+
log_buffer: Mutex<Vec<String>>,
3126
}
3227

3328
impl FileHandler {
3429
pub fn new(file: String) -> Self {
3530
Self {
3631
file,
37-
log_buffer: Vec::new(),
32+
log_buffer: Mutex::new(Vec::new()),
3833
}
3934
}
35+
}
4036

41-
/// Logs a message to the file.
42-
fn log(&mut self, log_level: LogLevel, message: String) {
43-
let timestamp = SystemTime::now()
37+
impl Handler for FileHandler {
38+
fn log(&self, record: &Record) {
39+
let timestamp = record
40+
.timestamp
4441
.duration_since(SystemTime::UNIX_EPOCH)
4542
.unwrap()
4643
.as_secs();
4744

48-
let log_message = format!("[{}]-[{:?}]: {}", timestamp, log_level, message);
45+
let log_message =
46+
format!("[{}]-[{:?}]: {}", timestamp, record.level, record.message);
4947

50-
let colored_message = match log_level {
48+
// Preserve existing behavior: color codes even in file output.
49+
let colored_message = match record.level {
5150
LogLevel::TRACE => format!("\x1B[37m{}\x1B[0m", log_message),
5251
LogLevel::DEBUG => format!("\x1B[35m{}\x1B[0m", log_message),
5352
LogLevel::INFO => format!("\x1B[32m{}\x1B[0m", log_message),
@@ -56,14 +55,15 @@ impl FileHandler {
5655
LogLevel::FATAL => format!("\x1B[31;1m{}\x1B[0m", log_message),
5756
};
5857

59-
self.log_buffer.push(colored_message);
58+
let mut buf = self.log_buffer.lock().unwrap();
59+
buf.push(colored_message);
6060

6161
// Flush buffer every ten messages.
62-
if self.log_buffer.len() < 10 {
62+
if buf.len() < 10 {
6363
return;
6464
}
6565

66-
let log_message = self.log_buffer.join("\n");
66+
let log_message = buf.join("\n");
6767

6868
let mut file = OpenOptions::new()
6969
.append(true)
@@ -75,61 +75,37 @@ impl FileHandler {
7575
.write_all(log_message.as_bytes())
7676
.expect("Unable to write data");
7777

78-
self.log_buffer.clear();
79-
}
80-
}
81-
82-
impl Handler for FileHandler {
83-
fn trace(&mut self, message: String) {
84-
self.log(LogLevel::TRACE, message)
85-
}
86-
87-
fn debug(&mut self, message: String) {
88-
self.log(LogLevel::DEBUG, message)
89-
}
90-
91-
fn info(&mut self, message: String) {
92-
self.log(LogLevel::INFO, message)
93-
}
94-
95-
fn warn(&mut self, message: String) {
96-
self.log(LogLevel::WARN, message)
97-
}
98-
99-
fn error(&mut self, message: String) {
100-
self.log(LogLevel::ERROR, message)
101-
}
102-
103-
fn fatal(&mut self, message: String) {
104-
self.log(LogLevel::FATAL, message)
78+
buf.clear();
10579
}
10680
}
10781

10882
#[derive(Debug, Clone, PartialEq, PartialOrd)]
109-
/// A handler that prints colored log lines to stdout.
11083
pub struct ConsoleHandler {
11184
name: String,
11285
}
11386

11487
impl ConsoleHandler {
11588
pub fn new(name: &str) -> Self {
116-
return Self {
89+
Self {
11790
name: name.to_string(),
118-
};
91+
}
11992
}
93+
}
12094

121-
fn log(&mut self, log_level: LogLevel, message: String) {
122-
let timestamp = SystemTime::now()
95+
impl Handler for ConsoleHandler {
96+
fn log(&self, record: &Record) {
97+
let timestamp = record
98+
.timestamp
12399
.duration_since(SystemTime::UNIX_EPOCH)
124100
.unwrap()
125101
.as_secs();
126102

127103
let log_message = format!(
128104
"[{}]-[{:?}]-[{}]: {}",
129-
timestamp, log_level, self.name, message
105+
timestamp, record.level, self.name, record.message
130106
);
131107

132-
let colored_message = match log_level {
108+
let colored_message = match record.level {
133109
LogLevel::TRACE => format!("\x1B[37m{}\x1B[0m", log_message),
134110
LogLevel::DEBUG => format!("\x1B[35m{}\x1B[0m", log_message),
135111
LogLevel::INFO => format!("\x1B[32m{}\x1B[0m", log_message),
@@ -141,29 +117,3 @@ impl ConsoleHandler {
141117
println!("{}", colored_message);
142118
}
143119
}
144-
145-
impl Handler for ConsoleHandler {
146-
fn trace(&mut self, message: String) {
147-
self.log(LogLevel::TRACE, message);
148-
}
149-
150-
fn debug(&mut self, message: String) {
151-
self.log(LogLevel::DEBUG, message);
152-
}
153-
154-
fn info(&mut self, message: String) {
155-
self.log(LogLevel::INFO, message);
156-
}
157-
158-
fn warn(&mut self, message: String) {
159-
self.log(LogLevel::WARN, message);
160-
}
161-
162-
fn error(&mut self, message: String) {
163-
self.log(LogLevel::ERROR, message);
164-
}
165-
166-
fn fatal(&mut self, message: String) {
167-
self.log(LogLevel::FATAL, message);
168-
}
169-
}

0 commit comments

Comments
 (0)