Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: log the function inputs #2

Merged
merged 5 commits into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading