Некоторое время назад мне пришла в голову идея сделать логирование в 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