An extremely high performance logging system for clients (iOS, Android, Desktop), written in Rust.

Overview

Pinenut Log

An extremely high performance logging system for clients (iOS, Android, Desktop), written in Rust.

codecov Crates.io Cocoapods Version

Overview

Architecture

Compression

Pinenut supports streaming log compression, it uses the Zstandard (aka zstd), a high performance compression algorithm that has a good balance between compression rate and speed.

Encryption

Pinenut uses the AES 128 algorithm for symmetric encryption during logging. To prevent embedding the symmetric key directly into the code, Pinenut uses ECDH for key negotiation (RSA is not used because its key are too long). When initializing the Logger, there is no need to provide the symmetric encryption key, instead the ECDH public key should be passed.

Pinenut uses secp256r1 elliptic curve for ECDH. You can generate the secret and public keys for encryption yourself, or use Pinenut's built-in command line tool: pinenut-cli.

Buffering

In order to minimize IO frequency, Pinenut buffers the log data before writing to the file. Client programs may exit unexpectedly (e.g., crash), Pinenut uses mmap as buffer support, so that if the program unexpectedly exits, the OS can still help to persist the buffered data. The next time the Logger is initialized, the buffered data is automatically read and written back to the log file.

In addition, Pinenut implements a double-buffering system to improve buffer read/write performance and prevent asynchronous IOs from affecting logging of the current thread.

Extraction

With Pinenut, we don't need to retrieve all the log files in the directory to extract logs, it provides convenient extraction capabilities and supports extraction in time ranges with minute granularity.

Parsing

The content of Pinenut log files is a special binary sequence after encoding, compression and encryption, and we can parse the log files using the parsing capabilities provided by Pinenut.

Installation

Pinenut provides APIs for these languages: Swift, Rust. Kotlin will be supported in the future.

Swift Package Manager

.package(url: "https://github.com/TangentW/Pinenut.git", from: "0.0.1")

CocoaPods

pod 'Pinenut'

Rust Cargo

[dependencies]
pinenut-log = 0.0.1

Usage

Pinenut's APIs are generally similar regardless of the language used.

Logger Initialization

Pinenut uses a Logger instance for logging. Before we initialize the Logger, we need to pass in the logger identifier and the path to the directory where the log files are stored to construct the Domain structure.

We can customize the Logger by explicitly specifying Config, see the API documentation for details.

Swift Code
let domain = Domain(identifier: "MyApp", directory: "/path/to/dir")
let config = Config(key: "Public Key Base64", compressionLevel: 10)
let logger = Logger(domain: domain, config: config)
Rust Code
let domain = Domain::new("MyApp".into(), "/path/to/dir".into());
let config = Config::new().key_str(Some("Public Key Base64")).compression_level(10);
let logger = Logger::new(domain, config);

Logging

Just construct the Record and call the log method.

Swift Code

Swift provides more convenient APIs for logging:

logger.log(.info, "Hello World")
logger.log(.debug, tag: "MyModule", "Debug Message")

// `Logger` provides APIs for logging levels.
logger.info("Hello World")
logger.error("Error message")
logger.debug(tag: "MyModule", "Debug message")

// Flushes any buffered records asynchronously.
logger.flush()
Rust Code

Records can be constructed in Rust via the Builder pattern:

// Builds `Meta` & `Record`.
let meta = Meta::builder().level(Level::Info).build();
let record = Record::builder().meta(meta).content("Hello World").build();
logger.log(&record);

// Flushes any buffered records asynchronously.
logger.flush();

See the API documentation for details.

Extraction

Just call the extract method to extract the logs for the specified time range (with minute granularity) and write them to the destination file.

Swift Code
let domain = Domain(identifier: "MyApp", directory: "/path/to/dir")
let range = Date(timeIntervalSinceNow: -1800)...Date()

do {
    try Logger.extract(domain: domain, timeRange: range, destPath: "/path/to/destination")
} catch {
    print("Error: \(error)")
}
Rust Code
let domain = Domain::new("MyApp".into(), "/path/to/dir".into());
let now = chrono::Utc::now();
let range = now.sub(Duration::from_secs(1800))..=now;

if let Err(err) = pinenut_log::extract(domain, range, "/path/to/destination") {
    println!("Error: {err}");
}

Note: The content of the extracted file is still a binary sequence that has been encoded, compressed, and encrypted. We need to parse it to see the log text content that is easy to read.

Parsing

You can use the parse function for log parsing, and you can specify the format of the log parsed text. See the API documentation for details.

Swift Code
do {
    try Logger.parse(path: path, to: dest, secretKey: secretKey)
} catch {
    print("Error: \(error)")
}
Rust Code
// Specifies the `DefaultFormater` as the log formatter.
if let Err(err) = pinenut_log::parse_to_file(&path, &output, secret_key, DefaultFormatter) {
    println!("Error: {err}");
}

Or use the built-in command line tool pinenut-cli:

$ pinenut-cli parse ./my_log.pine \
    --output ./plain.log          \
    --secret-key XXXXXXXXXXX

Keys Generation

Before initializing the Logger or parsing the logs, you need to have the public and secret keys ready (The public key is used to initialize the Logger and the secret key is used to parse the logs).

You can use pinenut-cli to generate this pair of keys:

$ pinenut-cli gen-keys

Benchmark

Some of Pinenut's designs are inspired by Xlog, here's a comparison of their benchmarks.

Both logging libraries support Zstd, so the benchmark will be run with both using the same version of the zstd library (v1.5.5) and a compression level of 10.

Execution on iPhone 12 with iOS 15.5.

Benchmark

Library Processed Log Records per Second (Speed)
Pinenut 447460
Xlog 317473

TODO

  • Level Filter
  • Kotlin APIs

License

Pinenut is released under the MIT license. See LICENSE for more details.

You might also like...
A beautiful, tiny traceback and logging library supporting #![no_std] rust.

breadcrumbs Breadcrumbs is a beautiful, tiny traceback and logging library for Rust that offers seamless integration with #![no_std], multi-threading

Application microframework with command-line option parsing, configuration, error handling, logging, and shell interactions
Application microframework with command-line option parsing, configuration, error handling, logging, and shell interactions

Abscissa is a microframework for building Rust applications (either CLI tools or network/web services), aiming to provide a large number of features w

✨ sleek typing tui with visualized results and historical logging
✨ sleek typing tui with visualized results and historical logging

thokr ✨ sleek typing tui with visualized results and historical logging Usage For detailed usage run thokr -h. thokr 0.4.1 sleek typing tui with visua

Logging for text that should stay in the same place in a console.

console_static_text Crate for logging text that should stay in the same place in a console. This measures words to handle wrapping and has some consol

A super simple but lightweight logging library that tries to capture the most important (status) information.

Hackerlog A super simple but lightweight logging library that tries to capture the most important (status) information. The following is supported: Lo

An extremely fast glob matching library in Rust.

glob-match An extremely fast glob matching library with support for wildcards, character classes, and brace expansion. Linear time matching. No expone

Extremely simple http rust servers :snowboarder:

Snowboard 🏂 An extremelly simple library for fast & simple TCP servers in rust [Request a feature/Report a bug] Quick start To get started with Snowb

A fully modular window manager, extremely extensibile and easily approachable.

AquariWM is a fully modular window manager, allowing extreme extensibility while remaining easily approachable. Installation AquariWM is currently in

Maccha is an extremely extensible and themable power menu for Windows, macOS, and Linux.

Maccha I hate coffee. Maccha is an extremely extensible and themable power menu for Windows, macOS, and Linux. Plugins Plugins are written in Rust (ot

Releases(0.0.1)
Owner
Tangent
A lonely monster.
Tangent
Simple template to use csr and ssr leptos with tauri for ios/android/windows/macos/linux and web dev

Tailwind-Leptos-Tauri Template Simple template to use csr and ssr leptos with tauri for ios/android/windows/macos/linux and web dev Just clone the rep

Victor Batarse 11 Mar 10, 2024
⚡ An extremely fast cross-compatible system information tool.

Lightfetch A extremely fast command-line system information tool written in Rust ⚡ . Gallery Sadly there isn't much to showcase right now. Download Av

bwtecode 2 Sep 12, 2022
⚡ An extremely fast cross-compatible system information tool.

Lightfetch A extremely fast command-line system information tool written in Rust ⚡ . Gallery Sadly there isn't much to showcase right now. Download Av

bwtecode 2 Sep 12, 2022
RedMaple offers an oppinionated yet extremely flexible data modeling system based on events for back-end applications.

RedMaple offers an oppinionated yet extremely flexible data modeling system based on events for back-end applications.

Amir Alesheikh 4 Mar 5, 2023
High-performance asynchronous computation framework for system simulation

Asynchronix A high-performance asynchronous computation framework for system simulation. What is this? Warning: this page is at the moment mostly addr

Asynchronics 7 Dec 7, 2022
A minimal file exchange server designed for clients with browsers only.

XIAO-Files Xiao-Files is a minimal file exchange server designed for clients with browsers only. Example Let's say we have a host with IP 10.8.20.1, a

EvianZhang 3 Apr 2, 2024
An extremely fast Python linter, written in Rust.

Ruff An extremely fast Python linter, written in Rust. Linting the CPython codebase from scratch. ⚡️ 10-100x faster than existing linters ?? Installab

Charlie Marsh 5.1k Dec 30, 2022
Helps cargo build and run apps for iOS

cargo-xcodebuild Helps cargo build and run apps for iOS. ?? ⚙️ ?? Setup You need to install Xcode (NOT just Command Line Tools!), xcodegen, cargo-xcod

Igor Shaposhnik 29 Nov 22, 2022
Middleware/ios shortcut to setup alarms automatically based on the first class

Webuntis alarm This is a small little "middleware" / web server intended to connect to a webuntis timetable used in german schools which i wrote when

raizo 3 Dec 30, 2022
A simple tool for extracting files from iOS backup archive.

iBackupExtractor A simple tool for extracting files from iOS backup archive. iOS backup files are not stored with their original directory layouts. Re

Cyandev 132 Oct 10, 2023