Java for Beginner
870 subscribers
1.01K photos
275 videos
14 files
1.69K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Итак ребят. Новая статья. 💃

С пылу с жару. Специально для вас)))

Оцениваем
🙂
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Что такое CAS (Compare-And-Swap) операции? 🤓

Ответ:

CAS — это атомарная инструкция процессора, которая сравнивает значение в памяти с ожидаемым значением, и если они равны, заменяет его на новое.

Выполняется атомарно (одна инструкция).

В Java CAS реализован через sun.misc.Unsafe и используется в атомарных классах (AtomicInteger, AtomicLong, AtomicReference) и в ConcurrentHashMap.

CAS — основа неблокирующих (lock-free) алгоритмов, которые работают быстрее synchronized при низкой конкуренции, так как не переводят поток в режим ожидания.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
История технологии сегодня — 20 мая

ℹ️ Кто родился в этот день

Исаа́к (Ю́зик) Я́ковлевич Померанчу́к (7 (20) мая 1913, Варшава — 14 декабря 1966, Москва) — советский физик-теоретикакадемик АН СССР (1964; член-корреспондент 1953).

Уильям Реддингтон Хьюлетт (англ. William Reddington Hewlett, 20 мая 1913 — 12 января 2001) — американский инженер, соучредитель компании «Hewlett-Packard» (HP, вместе с Дэвидом Паккардом).

Эмиль Берлинер (англ. Emile Berliner; 20 мая 1851, Ганновер — 3 августа 1931, Вашингтон) — американский изобретатель граммофона и микрофона, конструктор летательных аппаратов и общественный деятель.


🌐 Знаковые события

1891 — изобретатель Томас Эдисон показал общественности кинетоскоп, машину движущегося изображения.

1977 — первый полёт советского истребителя четвёртого поколения Су-27.



#Biography #Birth_Date #Events #20мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Раздел 9. Исключения, логирование, отладка

Глава 2. Логирование (Logging)

Логирование исключений — правильная передача throwable последним параметром

SLF4J анализирует последний аргумент метода логирования. Если он является экземпляром java.lang.Throwable, фреймворк обрабатывает его отдельно от параметров подстановки: исключение передается в appender для вывода полного стектрейса, а не встраивается в текст сообщения через {}.
// Правильно: throwable — последний параметр, SLF4J выведет стектрейс
logger.error("Payment processing failed for order {}", orderId, exception);

Здесь orderId подставляется в {}, а exception передается как объект Throwable. Logback или Log4j2 извлекают из него класс, сообщение и полный стектрейс, форматируя их согласно layout-конфигурации.
Механизм работает для любого количества параметров.

При одном аргументе-исключении и отсутствии placeholder-ов SLF4J использует сообщение исключения как текст лога и дополняет его стектрейсом:
// SLF4J интерпретирует exception как Throwable, а не как параметр подстановки
logger.error("Database connection lost", exception);



Проблема logger.error(e.getMessage(), e)

Этот паттерн встречается в коде, где разработчик хочет, чтобы текст лога совпадал с сообщением исключения.

Однако он порождает несколько проблем:
Дублирование сообщения. Если layout настроен на вывод %ex или %exception, стектрейс начинается с имени класса исключения и его getMessage(). Таким образом, сообщение исключения появляется дважды: в заголовке лога и в начале стектрейса.
// Вывод при logger.error(e.getMessage(), e)
2024-01-15 10:23:14 ERROR Connection timeout after 30000ms
java.net.SocketTimeoutException: Connection timeout after 30000ms
at java.net.SocketInputStream.socketRead0(Native Method)
...

Первая строка повторяет содержимое второй, увеличивая объем лога без добавления информации.

Потеря контекста. e.getMessage() часто содержит только техническое описание, лишенное бизнес-контекста. Сравните:
// Антипаттерн: что за заказ? какой шлюз?
logger.error(e.getMessage(), e);

// Правильно: контекст в сообщении, детали в стектрейсе
logger.error("Payment failed for order {} via gateway {}", orderId, gatewayId, e);


Риск null-сообщения.
Не все исключения имеют непустое сообщение. NullPointerException без кастомного сообщения вернет null, и logger.error(null, e) приведет к неинформативной строке null в заголовке лога.

Невозможность параметризации. Форма logger.error(e.getMessage(), e) не позволяет добавить параметры контекста, так как место для {} занято самим сообщением исключения.


#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍4
Правильный паттерн: контекст + throwable

Рекомендуемый подход — формировать описательное сообщение с бизнес-контекстом, передавая исключение последним параметром:
public void transferFunds(String fromAccount, String toAccount, BigDecimal amount) {
try {
bankingGateway.transfer(fromAccount, toAccount, amount);
logger.info("Transfer completed: {} -> {}, amount {}", fromAccount, toAccount, amount);
} catch (BankingException e) {
logger.error("Transfer failed: {} -> {}, amount {}, reason: {}",
fromAccount, toAccount, amount, e.getMessage(), e);
}
}

В этом примере заголовок лога содержит все параметры операции, позволяя оператору понять, какой именно перевод не удался, не разворачивая стектрейс. Стектрейс доступен для детального анализа, но не загромождает основное сообщение.
Особый случай: логирование без дополнительного контекста

Если метод перехватывает исключение только для логирования перед повторным выбросом, и дополнительного контекста не требуется, достаточно передать само исключение:
try {
executeOperation();
} catch (IOException e) {
logger.error("Operation failed", e);
throw new ServiceException("Execution error", e);
}

Здесь "Operation failed" — это статический префикс, а вся диагностическая информация содержится в стектрейсе исключения. Это допустимо, когда исключение само по себе достаточно информативно и уже содержит все необходимые детали.


Логирование исключений в Stream API и лямбдах

При обработке коллекций часто требуется логировать ошибку для конкретного элемента, но продолжить обработку остальных. Исключение передается в логгер стандартным образом:
List<String> processed = items.stream()
.map(item -> {
try {
return processor.process(item);
} catch (ProcessingException e) {
logger.warn("Skipping item {}: {}", item.getId(), e.getMessage(), e);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());


Важно: при логировании внутри catch-блока исключение должно оставаться доступным для дальнейшей обработки. Если метод глотает исключение без логирования или повторного выброса, информация о сбое теряется безвозвратно.


#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍4
Что выведет код?

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Task200526 {
private static final Logger log = LoggerFactory.getLogger(Task200526.class);

public static void main(String[] args) {
try {
throw new RuntimeException("BOOM");
} catch (Exception e) {
log.error("Error occurred: {}", e);
}
}
}



#Tasks
👍4
Что такое ForkJoinPool и RecursiveTask? 🤓

Ответ:

ForkJoinPool — это специальный пул потоков, реализующий алгоритм work-stealing (воровства задач).

Каждый поток имеет свою очередь задач. Когда поток завершает свои задачи, он может "украсть" задачу из очереди другого потока. 

RecursiveTask<V> — это абстрактный класс для задач, которые возвращают результат и могут разделяться (fork) на подзадачи и объединяться (join).

Классический пример — рекурсивные алгоритмы, такие как быстрая сортировка, слияние массивов, вычисление чисел Фибоначчи. Используется в parallelStream().


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологии сегодня — 21 мая

ℹ️ Кто родился в этот день

Андре́й Дми́триевич Са́харов (21 мая 1921, Москва — 14 декабря 1989, Москва) — советский физик-теоретик, академик АН СССР, общественный деятель, диссидент и правозащитник. Один из создателей первой советской водородной бомбы.

Гаспа́р-Гюста́в де Кориоли́с (фр. Gaspard-Gustave de Coriolis; 21 мая 1792 — 19 сентября 1843) — французский математикмеханик и инженер. Больше всего известен работой, посвящённой изучению эффекта Кориолиса. Также известен теоремой об ускорениях в абсолютном и относительном движениях, называемой теорема Кориолиса.


🌐 Знаковые события

2019 — Microsoft выпустила Windows Server 2019.


#Biography #Birth_Date #Events #21мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
[Совет по Java #040]

Тема: Переменные в catch и finally не видны снаружи.

Проблема: Блоки trycatchfinally образуют собственную область видимости. Переменная, объявленная внутри блока try, недоступна в блоках catch и finally.

Это приводит к распространенной ошибке: разработчик объявляет и инициализирует ресурс (например, BufferedReader) внутри try, а затем пытается закрыть его в finally. Код не компилируется с ошибкой "cannot find symbol". В попытке исправить это, некоторые объявляют переменную вне блока, но инициализируют её null, а затем в finally проверяют на null. Такой подход громоздок и чреват NullPointerException, если инициализация выбросила исключение. Кроме того, если ресурс поддерживает AutoCloseable, ручное закрытие в finally излишне и опасно (можно забыть закрыть, или исключения при закрытии перекроют исходное).

Решение: Начиная с Java 7, предпочтительный способ — try-with-resources. Ресурс объявляется в круглых скобках после try и автоматически закрывается после выполнения блока. Он доступен внутри trycatch и даже finally (хотя finally обычно не нужен). Если try-with-resources недоступен (старые версии Java или ресурс не реализует AutoCloseable), объявляйте переменную вне блока try, инициализируйте её значением null, затем в finally проверяйте на null перед закрытием. Однако первый вариант значительно чище и безопаснее.

public class TryCatchScope {

//Антипаттерн: переменная объявлена в try, недоступна в finally
public static void badScope() {
try {
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
String line = reader.readLine();
} catch (IOException e) {
System.err.println(e);
} finally {
// reader.close(); // Ошибка компиляции: reader не виден!
}
}

//Громоздкое ручное управление (не рекомендуется)
public static void manualManagement() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
String line = reader.readLine();
} catch (IOException e) {
System.err.println(e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// Проглатывание или логирование
}
}
}
}

//Решение: try-with-resources (лучший способ)
public static void goodTryWithResources() throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
// reader доступен здесь
} catch (IOException e) {
System.err.println("Ошибка: " + e);
// reader уже закрыт автоматически
}
}

//Если ресурс не реализует AutoCloseable, объявляйте вне try
public static void legacyResource() {
final int[] fileDescriptor = { -1 }; // имитация
try {
fileDescriptor[0] = openNativeResource();
} finally {
if (fileDescriptor[0] != -1) {
closeNativeResource(fileDescriptor[0]);
}
}
}

private static int openNativeResource() { return 42; }
private static void closeNativeResource(int fd) { }
}


Объяснение:
 Область видимости переменной в Java ограничена блоком, в котором она объявлена. Внутри try создается локальная переменная, которая уничтожается после выхода из блока, поэтому finally её не видит.

try-with-resources решает проблему иначе: ресурсы объявляются в специальной секции, их область видимости распространяется на trycatch и finally. Кроме того, компилятор генерирует правильный код закрытия с подавленными исключениями. Даже если вы не используете catch, блок finally становится не нужен.

#Java #советы
👍7
Что выведет код?

import java.io.*;

public class Task210526 {
public static void main(String[] args) throws IOException {
BufferedReader reader = null;
String result = "";

try {
reader = new BufferedReader(new StringReader("hello"));
result = reader.readLine();
throw new RuntimeException("error");
} catch (RuntimeException | IOException e) {
reader.close();
result = "catch";
} finally {
reader.close();
}

System.out.println(result);
}
}


#Tasks
👍2
Варианты ответа:
Anonymous Quiz
25%
hello
56%
catch
19%
Исключение IOException
0%
null
👍4
Что такое stamped lock (StampedLock)? 🤓

Ответ:

StampedLock (Java 8) — это альтернатива ReentrantReadWriteLock, которая поддерживает оптимистическое чтение.

Он возвращает "штамп" (long), который проверяется при попытке преобразования в полную блокировку. Оптимистическое чтение не блокирует запись и не требует блокировок, но после чтения нужно проверить, не изменились ли данные. Если изменились — можно повторить чтение с пессимистичной блокировкой.

Это повышает производительность в сценариях с частыми чтениями и редкими записями. Не поддерживает реентерабельность.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологии сегодня — 22 мая

ℹ️ Кто родился в этот день

Па́вел Алексе́евич Зару́бин (10 (22) мая 1816, посад Пучеж, Костромская губерния — 31 июля (12 августа) 1886, Санкт-Петербург)русский механик-самоучка, изобретатель, землемер и писатель.
Получил известность благодаря созданию ряда оригинальных приборов для межевания (в том числе 
планиметра-самоката, за который был дважды удостоен Демидовской премии), а также литературным произведениям, реалистично описывавшим быт провинциального мещанства и оказавшим, по признанию самого писателя, влияние на раннее творчество А. М. Горького.

Уильям Стёрджен (англ. William Sturgeon, 22 мая 1783 года — 4 декабря 1850 года) — британский физик, электротехник и изобретатель, создал первые электромагниты и изобрёл первый английский работающий электродвигатель.

Джордж Хейлмейер (англ. George Harry Heilmeier; (22 мая 1936 года — 21 апреля 2014 года)) — американский инженер и менеджер.
В 1964 году исследовал электрооптические эффекты в 
жидких кристаллах, что привело к появлению плоских жидкокристаллических экранов в 1968 году.

Сю́дзи Накаму́ра (яп. 中村修二 Накамура Сю:дзи, род. 22 мая 1954) — японский и американский физик, изобретатель синего светодиода, лауреат Нобелевской премии по физике (2014), в настоящее время работает в Калифорнийском университете в Санта-Барбаре (США).


🌐 Знаковые события

1906 — братья Райт получили патент на свой летательный аппарат.

1911 — профессор Технологического института Борис Розинг получил изображения геометрических фигур на экране электронно-лучевой трубки — прообразы нынешнего телевизионного изображения.

1973 — Роберт Меткалф составил докладную записку для главы PARC о потенциале технологии Ethernet. Этот день общепринято считать днём изобретения данной технологии.

1990 - состоялся релиз программной оболочки Windows 3.0 компании Microsoft.


#Biography #Birth_Date #Events #22мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Раздел 9. Исключения, логирование, отладка

Глава 2. Логирование (Logging)

Конфигурация Logback через logback.xml (или logback-test.xml)

Logback ищет файл конфигурации в classpath в строго определенном порядке приоритетов. Первый найденный файл используется, остальные игнорируются.

Последовательность поиска:
logback-test.xml — предназначен для тестов, имеет наивысший приоритет
logback.xml — стандартная production-конфигурация
logback.groovy — альтернативный формат на языке Groovy
Автоматическая конфигурация через SPI (Service Provider Interface)
Базовая конфигурация по умолчанию — консольный вывод с уровнем DEBUG

Файл logback-test.xml размещается в src/test/resources/ и гарантирует, что тесты используют собственную конфигурацию независимо от production-настроек. Это критично для изоляции: тесты могут подавлять лишний вывод или направлять логи в память для верификации.

Структура XML-конфигурации

Корневой элемент <configuration> поддерживает атрибуты для управления поведением сканирования:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- scan="true" — автоматическая перезагрузка при изменении файла -->
<!-- scanPeriod — интервал проверки в секундах, минутах, часах -->
<!-- debug="true" — вывод внутренней диагностики Logback в консоль -->

<!-- Определение переменных свойств -->
<property name="LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>
<property name="LOG_DIR" value="/var/log/myapp"/>

<!-- Appenders -->
<!-- ... -->

<!-- Логгеры -->
<!-- ... -->

<!-- Корневой логгер -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>

Элемент <property> определяет переменные, доступные во всей конфигурации через синтаксис ${NAME}. Переменные могут ссылаться на системные свойства JVM (${user.home}), переменные окружения (${ENV_VAR:-default}) или внешние файлы свойств через <property file="..."/>.


ConsoleAppender: вывод в консоль

ConsoleAppender направляет логи в System.out или System.err. Это стандартный appender для development-окружений и контейнеризированных приложений, где stdout/stderr собираются Docker или Kubernetes.
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!-- Целевой поток: System.out (по умолчанию) или System.err -->
<target>System.out</target>

<!-- Фильтр уровня: пропускать только INFO и выше -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>

<!-- Кодировка вывода -->
<encoder>
<charset>UTF-8</charset>
<pattern>${LOG_PATTERN}</pattern>
</encoder>

<!-- Немедленный сброс буфера (для контейнеров) -->
<immediateFlush>true</immediateFlush>
</appender>

Элемент <filter> ограничивает проходящие сообщения. ThresholdFilter пропускает только сообщения с уровнем не ниже указанного. Это позволяет направлять в консоль только INFO и выше, даже если корневой уровень установлен на DEBUG — фильтр appender работает после фильтра логгера.

Для контейнеризированных приложений рекомендуется выводить логи в stdout без форматирования времени, так как Docker добавляет собственную временную метку:
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>
</encoder>
</appender>


#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍1
FileAppender и RollingFileAppender: вывод в файл

FileAppender
записывает в единственный файл без ограничения размера. Это опасно для production, так как файл растет бесконечно. RollingFileAppender расширяет FileAppender политиками ротации, автоматически архивируя и заменяя файлы при достижении условий.


Базовый FileAppender

<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${LOG_DIR}/application.log</file>
<append>true</append> <!-- Дописывать в существующий файл -->

<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>

<!-- Права доступа к создаваемым файлам (только Unix) -->
<prudent>false</prudent> <!-- true — безопасная запись из нескольких JVM -->
</appender>

Атрибут prudent="true" включает режим безопасной записи из нескольких JVM в один файл через FileChannel locks. Это снижает производительность, но предотвращает повреждение при кластерном развертывании.


RollingFileAppender с ротацией по размеру
<appender name="ROLLING_SIZE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/application.log</file>

<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<!-- Имя архивного файла с индексом -->
<fileNamePattern>${LOG_DIR}/application.%i.log.zip</fileNamePattern>
<!-- Максимальный индекс архива -->
<minIndex>1</minIndex>
<maxIndex>10</maxIndex>
</rollingPolicy>

<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<!-- Максимальный размер файла перед ротацией -->
<maxFileSize>100MB</maxFileSize>
</triggeringPolicy>

<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>

FixedWindowRollingPolicy с SizeBasedTriggeringPolicy создает архивы с числовыми индексами: application.1.log.zip, application.2.log.zip и так до maxIndex. Когда достигнут maxIndex, самый старый архив удаляется. Эта политика проста, но имеет ограничение: при перезапуске приложения индексация начинается с 1, что может привести к перезаписи существующих архивов.


RollingFileAppender с ротацией по времени
<appender name="ROLLING_TIME" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/application.log</file>

<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Шаблон имени архива с датой -->
<fileNamePattern>${LOG_DIR}/application.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- Хранить архивы за 30 дней -->
<maxHistory>30</maxHistory>
<!-- Общий лимит размера архивов -->
<totalSizeCap>3GB</totalSizeCap>
<!-- Очистка устаревших архивов при старте -->
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>

<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>

TimeBasedRollingPolicy использует дату в шаблоне fileNamePattern для определения периода ротации. Спецификатор %d{yyyy-MM-dd} означает ежедневную ротацию. %d{yyyy-MM-dd_HH} — почасовую, %d{yyyy-MM} — ежемесячную. Logback автоматически вычисляет ближайший момент ротации на основе наиболее мелкой единицы времени в шаблоне.

maxHistory удаляет архивы старше указанного количества периодов. totalSizeCap ограничивает суммарный размер всех архивов — когда лимит превышен, самые старые архивы удаляются независимо от maxHistory. cleanHistoryOnStart выполняет очистку при старте приложения, что полезно для долгоживущих сервисов, которые могут перезапускаться редко.

#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍1
Комбинированная ротация: время + размер

<appender name="ROLLING_COMBINED" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/application.log</file>

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/application.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- Ежедневная ротация, но если файл превысит 100MB — дополнительная ротация -->
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>

<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>

SizeAndTimeBasedRollingPolicy комбинирует оба подхода. %i — индекс, который инкрементируется при достижении maxFileSize в течение одного временного периода. Таким образом, за один день может быть создано несколько архивов: application.2024-01-15.0.log, application.2024-01-15.1.log и так далее. Это решает проблему чрезмерно больших файлов при высокой нагрузке.


Практические шаблоны

Стандартный шаблон для development:
<pattern>%d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>

%highlight раскрашивает уровень в цвет терминала: ERROR красный, WARN желтый, INFO зеленый, DEBUG и TRACE синий. %cyan применяет циановый цвет к имени логгера.


Production-шаблон без ANSI-цветов:
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n%rEx</pattern>

%rEx (root exception) выводит сокращенный стектрейс, исключая фреймы из стандартных библиотек, что существенно уменьшает объем лога при частых исключениях.


JSON-формат для систем агрегации:
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>

LogstashEncoder из библиотеки logstash-logback-encoder формирует структурированный JSON с полями timestamp, level, logger, message, thread, stack_trace и MDC-значениями. Это устраняет необходимость парсинга регулярными выражениями в ELK или Splunk.


Установка уровней: корневой и пакетные логгеры

Корневой логгер

Корневой логгер (root) является предком всех остальных логгеров. Его уровень применяется, когда для конкретного логгера уровень не задан явно.
<root level="WARN">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="ROLLING_TIME"/>
</root>

Здесь корневой уровень WARN означает, что по умолчанию выводятся только WARN и ERROR. Любой логгер без явного уровня наследует эту настройку.

Логгеры для пакетов и классов
Элемент <logger> позволяет переопределить уровень для конкретного имени логгера, формируя иерархию:
<!-- Уровень DEBUG для всего пакета сервисов -->
<logger name="com.example.service" level="DEBUG"/>

<!-- Уровень TRACE для конкретного класса при расследовании -->
<logger name="com.example.service.PaymentGateway" level="TRACE"/>

<!-- Отключение additivity для изоляции аудита -->
<logger name="com.example.audit" level="INFO" additivity="false">
<appender-ref ref="AUDIT_FILE"/>
</logger>


#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍1
Свойство additivity управляет наследованием appenders. По умолчанию true: сообщение, обработанное логгером com.example.service, передается также в appenders предков (com.example, com, root). При additivity="false" сообщение обрабатывается только указанными appenders и не поднимается выше.

Это критично для разделения потоков. Логгер аудита направляет сообщения только в файл аудита, не дублируя их в общий консольный вывод:
<appender name="AUDIT_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/audit.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/audit.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>90</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %msg%n</pattern>
</encoder>
</appender>

<logger name="com.example.audit" level="INFO" additivity="false">
<appender-ref ref="AUDIT_FILE"/>
</logger>


Полный пример конфигурации
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">

<property name="LOG_DIR" value="/var/log/myapp"/>
<property name="LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n%rEx"/>

<!-- Консоль: только INFO и выше, с цветами -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>
</encoder>
</appender>

<!-- Основной файл: DEBUG и выше -->
<appender name="APPLICATION" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/application.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>

<!-- Файл ошибок: только ERROR -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/error.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>90</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>

<!-- Аудит: изолированный поток -->
<appender name="AUDIT_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/audit.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/audit.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>365</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %msg%n</pattern>
</encoder>
</appender>

<!-- Логгеры пакетов -->
<logger name="com.example.service" level="DEBUG"/>
<logger name="org.springframework.web" level="WARN"/>
<logger name="org.hibernate.SQL" level="DEBUG"/>

<!-- Изолированный аудит -->
<logger name="com.example.audit" level="INFO" additivity="false">
<appender-ref ref="AUDIT_FILE"/>
</logger>

<!-- Корневой логгер -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="APPLICATION"/>
<appender-ref ref="ERROR_FILE"/>
</root>

</configuration>


#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍5