Git Product home page Git Product logo

penna's Introduction

Penna

Penna

a contour feather, a penna; a quill, a feather used for writing; a pen; a pencil.

version Maintainability CircleCI

Penna is an opinionated backend for slf4j that focuses on doing one thing right: Logging structured logs in json format to the console.

Warning!

Penna is currently in alpha and, while usable, has not been tested in production yet.

Please use with caution. Feedback, however, is very welcome.

Why use Penna?

Penna presents itself as an alternative to logback. It is designed for a specific use case: When you want to have structured logging, straight to the console. This might be a common use-case for jvm apps running in kubernetes. If that is your use case, you might prefer Penna over logback because:

  • Penna is specialized for this use-case, working out of the box with sane defaults;
  • It does not require any json library (or any dependency other than slf4j);
  • It is very optimized, with impressive performance when compared to logback;
  • It is also designed not consume almost any runtime memory, so it won't cause GC pressure;
  • If you want to configure, the extension config library penna-yaml-config allows you to configure Penna in yaml, which might be a more native configuration format for its runtime environment (i.e. kubernetes);

However, Penna doesn't try to replace logback for all its use cases. If you have to log in multiple formats, to a file or any other target, logback might still be your tool of choice.

Usage

Penna is a backend for slf4j, so you don't need to interact with it directly.

In order to use it, add it to the build manager of your preference, for example:

// gradle
runtimeOnly 'com.hkupty.penna:penna-core:0.8.0'

// Penna doesn't have any strict dependencies aside from slf4j.
implementation 'org.slf4j:slf4j-api:2.0.12'

โš ๏ธ Note that Penna is built targeting JVM 21+.

By default, you will get log level INFO enabled as well as the following fields:

  • timestamp
  • level
  • message
  • logger
  • thread
  • mdc
  • markers
  • data (slf4j's 2.0 .addKeyValue())
  • throwable

If you want to configure it, Penna provides a separate convenience library for configuring your log levels in yaml files:

# resources/penna.yaml
---
# Since version 0.8, penna-yaml-config supports setting up a file watcher
# so any updates to this file will be reflected immediately
watch: true
loggers:
    # All the loggers under `com.yourapp` will be configured to debug level.
    com.yourapp: { level: debug }
    org.noisylibrary: { level: warn }

If you want to use penna-yaml-config, you have to add it as a dependency:

runtimeOnly 'com.hkupty.penna:penna-yaml-config:0.8.0'

// penna-yaml-config is a thin layer and uses a yaml parsing libray under the hood.
// You can chose among jackson, snakeyaml (yaml 1.1) or snakeyaml engine (yaml 1.2)

// Jackson
runtimeOnly 'com.fasterxml.jackson.core:jackson-core:2.17.0'
runtimeOnly 'com.fasterxml.jackson.core:jackson-databind:2.17.0'
runtimeOnly 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.17.0'

// Snakeyaml
runtimeOnly 'org.yaml:snakeyaml:2.2'

// Snakeyaml engine
runtimeOnly 'org.snakeyaml:snakeyaml-engine:2.7'

Principles

Structured logging

Logging is supposed to provide meaningful information and, with the evolution of log processing platforms, it is oftentimes difficult to convey the right information as written, natural text, in a way that it both makes sense for humans and is easy for machines to process.

Instead, we should embrace the notion that logs are effectively data and should be treated as such.

Lightweight configuration

Penna comes packed with a sane defaults configuration that allows one to plug it and start using immediately. Although configuration is possible, by rolling with the shipped defaults one can already reap the benefits of structured logging without having to set up any configuration.

Unobtrusiveness

The logging framework should not draw out much attention. It should just work. With that in mind, Penna tries to be a simple yet effective component in your architecture. It should not require you to add in more dependencies. Instead, it should work with whatever you have available. Also, it should make its best effort to consume the fewer resources as possible, being efficient and sparing your app of GC pauses when under heavy load. Read more on our performance tests.

penna's People

Contributors

dependabot[bot] avatar hkupty avatar joschi avatar marksailes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

penna's Issues

Missing synchronization and multiline exception messages

I believe the lack of synchronization of penna.core.sink.SinkImpl#write calls across threads can cause message corruption.

For example, you can try this program:

import java.util.concurrent.Executors;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class StdoutTest {
    
    private static final Logger TEST_LOGGER = LoggerFactory.getLogger("testlogger");
    
    @Test
    void run() {
        try(var scope = Executors.newFixedThreadPool(10)) {
            for(int i = 0; i < 10; i++) {
                scope.submit(() -> {
                    try {
                        var ex = new IllegalArgumentException("wrong type!!!\nok???", new RuntimeException("hello", new ArrayIndexOutOfBoundsException(5)));
                        ex.addSuppressed(new RuntimeException());
                        throw ex;
                    } catch(Exception e) {
                        TEST_LOGGER.atInfo()
                            .addKeyValue("version", 5)
                            .addKeyValue("hello", "a\ncouple\nlines")
                            .setCause(e)
                            .addKeyValue("blah", ("[" + Thread.currentThread().threadId() + "]").repeat(1000))
                            .log("Hello \n{}!", "world");
                    }
                });
            }
        }
    }
}

Multiple messages will be occasionally intertwined at key "blah". And exceptions will occassionally be missing the text after "wrong type!!!" (either because there's something funky with how Jackson is being used, or Jackson is flushing/writing before adding "\n").

Missing version number

When using Penna the initialization message doesn't include the pennaVersion.

{"logger":"penna.api.audit.Logger","level":"INFO","message":"Penna initialized successfully","pennaVersion":"null"}

Expected: To show the Penna version

Actual: Currently showing null

gradle-wrapper.jar is missing

When creating a fresh clone of the repository and running ./gradlew build, the following error is being printed:

# ./gradlew build 
Error: Could not find or load main class org.gradle.wrapper.GradleWrapperMain
Caused by: java.lang.ClassNotFoundException: org.gradle.wrapper.GradleWrapperMain

This seems due to the fact that gradle-wrapper.jar hasn't been checked in.

๐Ÿ”— https://docs.gradle.org/8.0.2/userguide/gradle_wrapper.html

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.