Skip to content

Commit

Permalink
feat: log the function inputs (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
andylokandy authored Jun 16, 2024
1 parent b7489c8 commit ba8b7d5
Show file tree
Hide file tree
Showing 11 changed files with 305 additions and 142 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ env:

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Install Stable Rust
run: rustup toolchain install stable
- name: Use Stable Rust
run: rustup default stable
- name: Build
run: cargo build --verbose
- name: Run tests
Expand Down
7 changes: 3 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[package]
name = "logcall"
version = "0.1.5"
version = "0.1.6"
edition = "2021"
authors = ["andylokandy <[email protected]>"]
description = "An attribute macro that logs the function return value."
repository = "https://github.com/andylokandy/logfn"
documentation = "https://docs.rs/logfn"
repository = "https://github.com/andylokandy/logcall"
documentation = "https://docs.rs/logcall"
categories = ["development-tools::debugging"]
readme = "README.md"
keywords = ["log", "macro", "derive", "logging", "function"]
Expand All @@ -18,7 +18,6 @@ proc-macro = true
proc-macro-error = "1"
proc-macro2 = "1"
quote = "1"
# The macro `quote_spanned!` is added to syn in 1.0.84
syn = { version = "1.0.84", features = [
"full",
"parsing",
Expand Down
109 changes: 92 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,113 @@
# logcall

An attribute macro that logs the function return value.
`logcall` is a Rust procedural macro crate designed to automatically log function calls, their inputs, and their outputs. This macro facilitates debugging and monitoring by providing detailed logs of function executions with minimal boilerplate code.

This is a reimplementation of the [`log-derive`](https://crates.io/crates/log-derive) crate with [`async-trait`](https://crates.io/crates/async-trait) compatibility.
This is a re-implementation of the [`log-derive`](https://crates.io/crates/log-derive) crate with [`async-trait`](https://crates.io/crates/async-trait) compatibility.

## Installation

Add `logcall` to your `Cargo.toml`:

```toml
[dependencies]
logcall = "0.1"
```

## Usage

Import the `logcall` crate and use the macro to annotate your functions:

```rust
use logcall::logcall;

/// Logs the function call at the default `debug` level.
#[logcall]
fn add(a: i32, b: i32) -> i32 {
a + b
}

/// Logs the function call at the `info` level.
#[logcall("info")]
fn foo(a: usize) -> usize {
a + 1
fn multiply(a: i32, b: i32) -> i32 {
a * b
}

/// Logs `Ok` results at the `info` level and `Err` results at the `error` level.
#[logcall(ok = "info", err = "error")]
fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err("Division by zero".to_string())
} else {
Ok(a / b)
}
}

/// Logs errors at the `error` level. No log output for `Ok` variant.
#[logcall(err = "error")]
fn bar(a: usize) -> Result<usize, usize> {
Err(a + 1)
fn divide2(a: usize, b: usize) -> Result<usize, String> {
if b == 0 {
Err("Division by zero".to_string())
} else {
Ok(a / b)
}
}

#[logcall(ok = "info", err = "error")]
fn baz(a: usize) -> Result<usize, usize> {
Ok(a + 1)
/// Logs the function call with custom input logging format.
#[logcall(input = "a = {a:?}, ..")]
fn subtract(a: i32, b: i32) -> i32 {
a - b
}

fn main() {
env_logger::builder().filter_level(log::LevelFilter::Info).init();
foo(1);
bar(1).ok();
baz(1).ok();
env_logger::builder()
.filter_level(log::LevelFilter::Trace)
.init();

add(2, 3);
multiply(2, 3);
divide(2, 0).ok();
divide2(2, 0).ok();
subtract(2, 3);
}
```

### Log Output

// prints:
// [2023-07-22T06:55:10Z INFO main] foo() => 2
// [2023-07-22T06:55:10Z ERROR main] bar() => Err(2)
// [2023-07-22T06:55:10Z INFO main] baz() => Ok(2)
When the `main` function runs, it initializes the logger and logs each function call as specified:

```ignore
[2024-06-16T12:41:04Z DEBUG main] add(a = 2, b = 3) => 5
[2024-06-16T12:41:04Z INFO main] multiply(a = 2, b = 3) => 6
[2024-06-16T12:41:04Z ERROR main] divide(a = 2, b = 0) => Err("Division by zero")
[2024-06-16T12:41:04Z ERROR main] divide2(a = 2, b = 0) => Err("Division by zero")
[2024-06-16T12:41:04Z DEBUG main] subtract(a = 2, ..) => -1
```

## Customization

- **Default Log Level**: If no log level is specified, `logcall` logs at the `debug` level:
```rust,ignore
#[logcall]
```
- **Specify Log Level**: Use the macro parameters to specify log level:
```rust,ignore
#[logcall("info")]
- **Specify Log Levels for `Result`**: Use the `ok` and `err` parameters to specify log levels for `Ok` and `Err` variants:
```rust,ignore
#[logcall(err = "error")]
#[logcall(ok = "info", err = "error")]
```
- **Customize Input Logging**: Use the `input` parameter to customize the input log format:
```rust,ignore
#[logcall(input = "a = {a:?}, ..")]
#[logcall("info", input = "a = {a:?}, ..")]
#[logcall(ok = "info", err = "error", input = "a = {a:?}, ..")]
```

## Contributing

Contributions are welcome! Please submit pull requests or open issues to improve the crate.

## License

This project is licensed under the MIT License.
48 changes: 37 additions & 11 deletions examples/main.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,51 @@
use logcall::logcall;

/// Logs the function call at the default `debug` level.
#[logcall]
fn add(a: i32, b: i32) -> i32 {
a + b
}

/// Logs the function call at the `info` level.
#[logcall("info")]
fn foo(a: usize) -> usize {
a + 1
fn multiply(a: i32, b: i32) -> i32 {
a * b
}

/// Logs `Ok` results at the `info` level and `Err` results at the `error` level.
#[logcall(ok = "info", err = "error")]
fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err("Division by zero".to_string())
} else {
Ok(a / b)
}
}

/// Logs errors at the `error` level. No log output for `Ok` variant.
#[logcall(err = "error")]
fn bar(a: usize) -> Result<usize, String> {
Err(format!("{}", a + 1))
fn divide2(a: usize, b: usize) -> Result<usize, String> {
if b == 0 {
Err("Division by zero".to_string())
} else {
Ok(a / b)
}
}

#[logcall(ok = "info", err = "error")]
fn baz(a: usize) -> Result<usize, String> {
Ok(a + 1)
/// Logs the function call with custom input logging format.
#[logcall(input = "a = {a:?}, ..")]
fn subtract(a: i32, b: i32) -> i32 {
a - b
}

fn main() {
env_logger::builder()
.filter_level(log::LevelFilter::Info)
.filter_level(log::LevelFilter::Trace)
.init();
foo(1);
bar(1).ok();
baz(1).ok();

add(2, 3);
multiply(2, 3);
divide(2, 0).ok();
divide2(2, 0).ok();
subtract(2, 3);
}
Loading

0 comments on commit ba8b7d5

Please sign in to comment.