# Logcall
[](https://crates.io/crates/logcall)
[](https://crates.io/crates/logcall)
[](https://docs.rs/logcall/)
[](https://github.com/fast/logcall/actions)
[](https://crates.io/crates/logcall)
Logcall provides a `#[logcall]` attribute that logs function inputs and return values through the [`log`](https://crates.io/crates/log) facade. It keeps boilerplate low while making debugging and observability easy.
This is a reimplementation of [`log-derive`](https://crates.io/crates/log-derive) with async functions, [`async-trait`](https://crates.io/crates/async-trait), `Result`, and `Option` support.
## Installation
Logcall emits through `log`, so applications also need a logger. This example uses `logforth`:
```toml
[dependencies]
log = "0.4"
logcall = "0.2.0"
logforth = { version = "0.30", features = ["starter-log"] }
```
## Quick Start
Annotate functions with `#[logcall]` and configure logging with `logforth`:
```rust
use logcall::logcall;
use logforth::record::LevelFilter;
/// 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 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 divide2(a: usize, b: usize) -> Result<usize, String> {
a.checked_div(b).ok_or("divide by zero".into())
}
/// Logs `Some` values at the `info` level and `None` values at the `warn` level.
#[logcall(some = "info", none = "warn")]
fn find_even(value: i32) -> Option<i32> {
(value % 2 == 0).then_some(value)
}
/// Logs the function call with custom input logging format.
#[logcall(input = "a = {a:?}, ..")]
fn subtract(a: i32, b: i32) -> i32 {
a - b
}
/// Logs the function call with custom output logging format.
#[logcall(output = ": {:?}")]
fn negate(a: i32) -> i32 {
-a
}
/// Omits the return value from the log output.
#[logcall(output = "")]
fn ping(a: i32) -> i32 {
a
}
fn main() {
logforth::starter_log::stdout()
.filter(LevelFilter::All)
.apply();
add(2, 3);
multiply(2, 3);
divide(2, 0).ok();
divide2(2, 0).ok();
find_even(4);
find_even(3);
subtract(3, 2);
negate(5);
ping(42);
}
```
### Example Run
```bash
cargo run --example main
```
Sample output:
```plaintext
2026-06-12T18:18:14.935453+08:00 DEBUG main: main.rs:5 main::add(a = 2, b = 3) => 5
2026-06-12T18:18:14.935505+08:00 INFO main: main.rs:11 main::multiply(a = 2, b = 3) => 6
2026-06-12T18:18:14.935514+08:00 ERROR main: main.rs:17 main::divide(a = 2, b = 0) => Err("Division by zero")
2026-06-12T18:18:14.935520+08:00 ERROR main: main.rs:27 main::divide2(a = 2, b = 0) => Err("divide by zero")
2026-06-12T18:18:14.935525+08:00 INFO main: main.rs:33 main::find_even(value = 4) => Some(4)
2026-06-12T18:18:14.935529+08:00 WARN main: main.rs:33 main::find_even(value = 3) => None
2026-06-12T18:18:14.935533+08:00 DEBUG main: main.rs:39 main::subtract(a = 3, ..) => 1
2026-06-12T18:18:14.935537+08:00 DEBUG main: main.rs:45 main::negate(a = 5): -5
2026-06-12T18:18:14.935542+08:00 DEBUG main: main.rs:51 main::ping(a = 42)
```
## Attribute Arguments
Generated input and output formatting uses `Debug` by default. Supported log levels are `error`, `warn`, `info`, `debug`, and `trace`.
- `#[logcall]` logs every call at the `debug` level.
- `#[logcall("info")]` logs every call at the selected level.
- `#[logcall(ok = "info", err = "error")]` logs `Result` variants independently. Omit `ok` or `err` to skip that variant.
- `#[logcall(some = "info", none = "warn")]` logs `Option` variants independently. Omit `some` or `none` to skip that variant.
- `#[logcall(input = "...")]` replaces the argument portion of the message. The format string can reference arguments by name.
- `#[logcall(output = "...")]` replaces the return value portion of the message. Use `output = ""` to log only the call.
The macro supports sync functions, async functions, and async functions generated by `async-trait`.
## Minimum Supported Rust Version (MSRV)
This crate's minimum supported rustc version is 1.91.0.
The minimum Rust version can increase in minor releases. Patch releases keep the same minimum Rust version.
## Contributing
Contributions are welcome! Please submit pull requests or open issues to improve the crate.
## License
This project is licensed under the MIT License. See the `LICENSE` file for details.