Logy — логгер с человеческим лицом

в 9:30, , рубрики: java, library, log4j, logger, logging, open source, метки: , , , , ,

Некоторое время назад мне пришла в голову идея сделать логирование в Java более дружелюбным, простым и в тоже время достаточно гибким в настройке. Такие требования справедливы пожалуй, в средних и малых проекта, где можно обойтись без громоздкого log4j. Буквально за неделю, идея переросла в простенькую Java библиотеку с ни менее простым названием — logy.

Использование:

import static logy.Logy.*;

public class Test {
  public void test() {
    String s[] = {"a", "b"};
    warn("Can't find", quote(upper("c")), "in", group(quote(upper(scalar(s)))));
  }
}

Вывод:
29.06.2012 1:19:25 Test.test [WARN] :: Can't find "C" in ["A", "B"]

Как по мне, выглядит очень читабельно, благодаря синтаксическому сахару, DSL-like API и динамическому определению параметров логирования в момент вызова (читай без дополнительных полей public static final Logger logger = ... в классе).

О названии

Слово “logy” — переводится c английского как “тупой”. С одной стороны, название воспринимается как уменьшительно-ласкательное от “log”, с другой — намекает на узколобость (в хорошем смысле) и простоту библиотеки.

Особенности/возможности

  • занимает 17 кб в скомпилированном JAR файле
  • без зависимостей
  • DSL-like API: quote, group, upper, export, …
  • динамическое определение параметров логированя (без явной инициализации логгера)
  • логирование в файл/stdout/stderr
  • поддержка маски (“*”) в конфигурационных файлах
  • конфигурация в диапазоне “глобально”...“метод”

API

API logy представляет собой набор статических методов с переменным числом параметров, которые могут быть импортированы в проект одной строчкой:

import static logy.Logy.*;

5 уровней сообщений, в порядке приоритета: “debug”, “fine”, “info”, “warn”, “error”, представлены одноименными методами.

Пример:

error("Files", quote("file1", "file2"), "not found!").

Вывод:
Files "file1" "file2" not found!

Экспорт результатов преобразований в строку с помощью метода “export”.

Пример:

String s = export("The", quote(upper("message")), "can’t be delivered!");
System.out.println(s);

Вывод:
The "MESSAGE" can't be delivered!

Оборачивание параметров в кавычки методом “quote”.

Пример:

int arr[] = {1, 2, 3, 4};
info("Quotted values:", quote(scalar(arr), "a", "b"));

Вывод:
Quotted values: "1" "2" "3" "4" "a" "b"

Группировка результатов с помощью метода “group”.

String s[]= {"a", "b", "c"};
info("Grouped values:", group(scalar(s), 1, "d"));

Вывод:
Grouped values: [a, b, c, 1, d]

Изменение регистра параметров методами “upper” и “lower”.

Пример:

String s[]= {"a", "b", "c"};
info("Uppered values:", upper(scalar(s)));
info("Lowered values:", lower("A", "B", "C"));

Вывод:
Uppered values: A B C
Lowered values: a b c

Уточнение варианта использования параметра с помощью методов “scalar” и “array”.

Пример:

int arr[] = {1, 2, 3, 4};
info("Quotted array:", quote(array(arr)));
info("Quotted values:", quote(scalar(arr)));

Вывод:
Quotted array: "[1, 2, 3, 4]"
Quotted values: "1" "2" "3" "4"

Конфигурация

Конфигурационные файлы поддерживают следующие определения:

  • комментарии, начинающиеся с “#”
  • тройки вида “VARIABLE@SCOPE=VALUE”

Например, тройка для конфигурации глобального формата сообщений может выглядеть вот так:

format@=%date% %time %class% [%level%] %%%

Где доступны следующие переменные контекста:

  • %scope% — полный путь до метода, из которого вызван логгер
  • %class% — полный путь до класса, из метода которого вызван логгер
  • %method% — название метода, из которого вызван логгер
  • %date% — дата, в момент вызова логгера, в формате текущей локали
  • %time% — время в момент вызова логгера, в формате текущей локали
  • %level% — уровень сообщения логгера
  • %%% — сообщение логгера

Основной особенностью при задании области использования переменной является использование маски “*” в пути.

Рассмотрим простой пример. Пусть требуется логировать все сообщения в файл из классов-тестов и логировать в консоль из остальных классов только ошибки. Для этого создадим файл “properties.logy” в корне проекта, со следующим содержанием:

# глобальные настройки
level@=error
logger@=stream:err

# для классов заканчивающихся на “Test” и методов начинающихся с “test”
level@*Test.test*=debug
logger@*Test.test*=file:test.log

Планы

Я хочу, чтобы logy всегда оставался минималистичным инструментом, решающим узкий набор задач. Поэтому, в проект наверняка не будут масштабно вливаться новые фичи, например: поддержка логирования в БД, в сеть, и т.д. Целевая аудитория проекта — малые и средние проекты, где такие возможности скорее всего не понадобятся.

Единственное, что действительно не хватает logy сейчас, это а) поддержка нескольких логгеров для одной области использования (сейчас, к сожалению только один); б) корректная работа в многопоточной среде (по правде сказать, не проверял, но подозреваю, что будут проблемы, особенно при логировании в файл).

Эти изменения я планирую сделать в ближайшее время для версии 0.2.0.

PS

Конечно, я рассказал не обо всех возможностях библиотеки. Более подробную документацию (в процессе написания) можно будет найти на GitHub странице проекта.

Буду крайне рад фидбекам, форкам, пул-реквестам и баг репортам.

Что касается аналогов. Я не зря оставил этот вопрос напоследок. Честно признаться, я не особо старался найти похожую функционалом и возможностями библиотеку. Наверное потому, что хотел написать что-то полностью свое, или, мне просто надоело искать для себя отмазки вида “да уже придумали такое, пойду поем” перед каждой новой идей в моей голове, жаждущей реализации. Кроме того известно, что придумать что-то действительно новое почти невозможно, возможно — сделать это лучше чем другие.

Автор: spiff


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js