FileAppender и RollingFileAppender: вывод в файл
Базовый FileAppender
Атрибут
RollingFileAppender с ротацией по размеру
RollingFileAppender с ротацией по времени
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
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
Комбинированная ротация: время + размер
Практические шаблоны
Стандартный шаблон для development:
Production-шаблон без ANSI-цветов:
JSON-формат для систем агрегации:
Установка уровней: корневой и пакетные логгеры
Корневой логгер
Корневой логгер (
Здесь корневой уровень WARN означает, что по умолчанию выводятся только WARN и ERROR. Любой логгер без явного уровня наследует эту настройку.
Логгеры для пакетов и классов
Элемент
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
<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
Свойство
Это критично для разделения потоков. Логгер аудита направляет сообщения только в файл аудита, не дублируя их в общий консольный вывод:
Полный пример конфигурации
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
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
Что выведет код?
#Tasks
public class Task220526 {
public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder("Java");
StringBuilder sb2 = sb1.append("Script");
System.out.println(sb1 == sb2);
System.out.println(sb1.toString() == sb2.toString());
System.out.println(sb1.toString().equals(sb2.toString()));
}
}#Tasks
👍3
Варианты ответа:
Anonymous Quiz
35%
true true true
24%
true false true
18%
false false true
24%
true false false
👍2
Что такое Phaser? 🤓
Ответ:
Phaser — это более гибкая замена CyclicBarrier и CountDownLatch, появившаяся в Java 7.
Он поддерживает многофазную синхронизацию потоков, которые могут динамически регистрироваться и дерегистрироваться. Каждая фаза имеет номер.
Потоки вызывают arriveAndAwaitAdvance() — прибытие и ожидание перехода к следующей фазе. Phaser может использоваться для организации синхронизации в алгоритмах с несколькими итерациями (фазами), где количество участников меняется.
Поддерживает иерархию (родительские Phaser'ы).
#собеседование
Ответ:
Phaser — это более гибкая замена CyclicBarrier и CountDownLatch, появившаяся в Java 7.
Он поддерживает многофазную синхронизацию потоков, которые могут динамически регистрироваться и дерегистрироваться. Каждая фаза имеет номер.
Потоки вызывают arriveAndAwaitAdvance() — прибытие и ожидание перехода к следующей фазе. Phaser может использоваться для организации синхронизации в алгоритмах с несколькими итерациями (фазами), где количество участников меняется.
Поддерживает иерархию (родительские Phaser'ы).
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологии сегодня — 23 мая
Сегодня Java исполнился 31 год! 🎉
Изначально язык назывался Oak («Дуб»), разрабатывался Джеймсом Гослингом для программирования бытовых электронных устройств. Из-за того, что язык с таким названием уже существовал, Oak был переименован в Java. Назван в честь марки кофе Java, которая, в свою очередь, получила наименование одноимённого острова (Ява), поэтому на официальной эмблеме языка изображена чашка с горячим кофе. Существует и другая версия происхождения названия языка, связанная с аллюзией на кофемашину как пример бытового устройства, для программирования которого изначально язык создавался. В соответствии с этимологией в русскоязычной литературе с конца двадцатого и до первых лет двадцать первого века название языка нередко переводилось как Ява, а не транскрибировалось.
С середины 1990-х годов язык стал широко использоваться для написания клиентских приложений и серверного программного обеспечения. Тогда же определённое распространение получила технология Java-апплетов — графических Java-приложений, встраиваемых в веб-страницы; с развитием возможностей динамических веб-страниц в 2000-е годы технология стала применяться редко.
ℹ️ Кто родился в этот день
Роберт Артур Муг (Моуг; англ. Robert A. Moog, Bob Moog /ˈmoʊɡ/; 23 мая 1934 — 21 августа 2005) — американский изобретатель, предприниматель, пионер электронной музыки, известен как создатель синтезатора Муга.
Джон Ба́рди́н (англ. John Bardeen; 23 мая 1908, Мадисон, Висконсин, США — 30 января 1991, Бостон, Массачусетс, США) — американский физик, один из пяти человек, получивших за свою жизнь по две Нобелевские премии: в 1956 году за транзистор совместно с Уильямом Брэдфордом Шокли и Уолтером Браттейном и в 1972 году за основополагающую теорию обычных сверхпроводников совместно с Леоном Нилом Купером и Джоном Робертом Шриффером. Сейчас эта теория называется теорией Бардина — Купера — Шриффера, или просто БКШ-теория.
🌐 Знаковые события
1934 — первый полёт экспериментальной крылатой ракеты, спроектированной под руководством С. П. Королёва в ГИРД, оснащённой ГРД.
1995 — компания Sun официально представила Java и HotJava на выставке SunWorld '95.
#Biography #Birth_Date #Events #23мая
Сегодня Java исполнился 31 год! 🎉
Изначально язык назывался Oak («Дуб»), разрабатывался Джеймсом Гослингом для программирования бытовых электронных устройств. Из-за того, что язык с таким названием уже существовал, Oak был переименован в Java. Назван в честь марки кофе Java, которая, в свою очередь, получила наименование одноимённого острова (Ява), поэтому на официальной эмблеме языка изображена чашка с горячим кофе. Существует и другая версия происхождения названия языка, связанная с аллюзией на кофемашину как пример бытового устройства, для программирования которого изначально язык создавался. В соответствии с этимологией в русскоязычной литературе с конца двадцатого и до первых лет двадцать первого века название языка нередко переводилось как Ява, а не транскрибировалось.
С середины 1990-х годов язык стал широко использоваться для написания клиентских приложений и серверного программного обеспечения. Тогда же определённое распространение получила технология Java-апплетов — графических Java-приложений, встраиваемых в веб-страницы; с развитием возможностей динамических веб-страниц в 2000-е годы технология стала применяться редко.
Роберт Артур Муг (Моуг; англ. Robert A. Moog, Bob Moog /ˈmoʊɡ/; 23 мая 1934 — 21 августа 2005) — американский изобретатель, предприниматель, пионер электронной музыки, известен как создатель синтезатора Муга.
Джон Ба́рди́н (англ. John Bardeen; 23 мая 1908, Мадисон, Висконсин, США — 30 января 1991, Бостон, Массачусетс, США) — американский физик, один из пяти человек, получивших за свою жизнь по две Нобелевские премии: в 1956 году за транзистор совместно с Уильямом Брэдфордом Шокли и Уолтером Браттейном и в 1972 году за основополагающую теорию обычных сверхпроводников совместно с Леоном Нилом Купером и Джоном Робертом Шриффером. Сейчас эта теория называется теорией Бардина — Купера — Шриффера, или просто БКШ-теория.
1934 — первый полёт экспериментальной крылатой ракеты, спроектированной под руководством С. П. Королёва в ГИРД, оснащённой ГРД.
1995 — компания Sun официально представила Java и HotJava на выставке SunWorld '95.
#Biography #Birth_Date #Events #23мая
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5🍾3
С 09.05 по 22.05
Предыдущий пост(с 02.05 по 08.05)
Запись встреч/видео:
13. Kafka: переход от очереди задач к журналу событий
Keycloak с нуля: от первого токена до современной auth-архитектуры
Обучающие статьи:
[Совет по Java #035]
Тема: java.util.Timer создает один поток для всех задач.
[Совет по Java #037]
Тема: File.delete() не бросает исключение при неудаче.
[Совет по Java #038]
Тема: SimpleDateFormat не потокобезопасен.
[Совет по Java #039]
Тема: String.split() принимает регулярное выражение.
[Совет по Java #040]
Тема: Переменные в catch и finally не видны снаружи.
Раздел 9. Исключения, логирование, отладка
Глава 2. Логирование (Logging)
Подключение SLF4J + Logback в проект (Maven/Gradle). Базовый пример получения логгера
Уровни логирования: TRACE, DEBUG, INFO, WARN, ERROR. Когда что использовать. Иерархия и фильтрация
Параметризованные сообщения SLF4J: почему это лучше конкатенации строк
Логирование исключений — правильная передача throwable последним параметром
Конфигурация Logback через logback.xml (или logback-test.xml)
Полезные статьи и видео:
Java нас обманывает: скрытая цена чистого кода
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
Предыдущий пост(с 02.05 по 08.05)
Запись встреч/видео:
13. Kafka: переход от очереди задач к журналу событий
Keycloak с нуля: от первого токена до современной auth-архитектуры
Обучающие статьи:
[Совет по Java #035]
Тема: java.util.Timer создает один поток для всех задач.
[Совет по Java #037]
Тема: File.delete() не бросает исключение при неудаче.
[Совет по Java #038]
Тема: SimpleDateFormat не потокобезопасен.
[Совет по Java #039]
Тема: String.split() принимает регулярное выражение.
[Совет по Java #040]
Тема: Переменные в catch и finally не видны снаружи.
Раздел 9. Исключения, логирование, отладка
Глава 2. Логирование (Logging)
Подключение SLF4J + Logback в проект (Maven/Gradle). Базовый пример получения логгера
Уровни логирования: TRACE, DEBUG, INFO, WARN, ERROR. Когда что использовать. Иерархия и фильтрация
Параметризованные сообщения SLF4J: почему это лучше конкатенации строк
Логирование исключений — правильная передача throwable последним параметром
Конфигурация Logback через logback.xml (или logback-test.xml)
Полезные статьи и видео:
Java нас обманывает: скрытая цена чистого кода
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
👍1🔥1
История технологии сегодня — 24 мая
ℹ️ Кто родился в этот день
Алекса́ндр Алексе́евич Лема́нский (24 мая 1935, Москва — 27 сентября 2007, Капустин Яр, Ахтубинский район, Астраханская область) — советский и российский учёный, генеральный конструктор НПО «Алмаз», заведующий кафедрой «Радиолокация, радиоуправление и информатика» Факультета радиотехники и кибернетики МФТИ, доктор технических наук, профессор, руководитель работ по созданию системы С-400.
Даниель Габриель Фаренгейт (Фаренхайт; нем. Daniel Gabriel Fahrenheit; 24 мая 1686, Данциг (ныне — Гданьск, Польша) — 16 сентября 1736, Гаага) — немецкий физик, родившийся в Польше. В Нидерландах он впервые изготовил термометр и барометр. Вначале термоскопической жидкостью ему служил спирт, но затем около 1715 года он заменил спирт ртутью, чем достиг гораздо большей точности измерений. Фаренгейтом изготовлены также первый весовой ареометр и термобарометр. В 1721 году он открыл, что вода может быть охлаждена ниже точки замерзания и оставаться в жидком состоянии; работал также над устройством машины для осушения местностей, подвергшихся наводнениям. Единица измерения температуры градус Фаренгейта (°F) была названа в его честь.
🌐 Знаковые события
1949 — пуск первой советской геофизической ракеты В-1А. Начало регулярных научных исследований верхних слоёв атмосферы.
2001 — в русской Википедии появилась первая статья.
2006 — запущен проект Wikimapia.
#Biography #Birth_Date #Events #24мая
Алекса́ндр Алексе́евич Лема́нский (24 мая 1935, Москва — 27 сентября 2007, Капустин Яр, Ахтубинский район, Астраханская область) — советский и российский учёный, генеральный конструктор НПО «Алмаз», заведующий кафедрой «Радиолокация, радиоуправление и информатика» Факультета радиотехники и кибернетики МФТИ, доктор технических наук, профессор, руководитель работ по созданию системы С-400.
Даниель Габриель Фаренгейт (Фаренхайт; нем. Daniel Gabriel Fahrenheit; 24 мая 1686, Данциг (ныне — Гданьск, Польша) — 16 сентября 1736, Гаага) — немецкий физик, родившийся в Польше. В Нидерландах он впервые изготовил термометр и барометр. Вначале термоскопической жидкостью ему служил спирт, но затем около 1715 года он заменил спирт ртутью, чем достиг гораздо большей точности измерений. Фаренгейтом изготовлены также первый весовой ареометр и термобарометр. В 1721 году он открыл, что вода может быть охлаждена ниже точки замерзания и оставаться в жидком состоянии; работал также над устройством машины для осушения местностей, подвергшихся наводнениям. Единица измерения температуры градус Фаренгейта (°F) была названа в его честь.
1949 — пуск первой советской геофизической ракеты В-1А. Начало регулярных научных исследований верхних слоёв атмосферы.
2001 — в русской Википедии появилась первая статья.
2006 — запущен проект Wikimapia.
#Biography #Birth_Date #Events #24мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Почему все-таки программирование?
Мне, 40-летнему человеку, по теории, должно было быть сложно менять профессию.
Тем более, я уже успел получить несколько других и добиться в них немалого успеха.
Так почему же я решился на такую авантюру? (а по другому, мои родные это не называли😂 )
Вот некоторые из тех принципов, которые определили пройденный путь:
1. Успех в определенной профессии != достойной зарплате и условиям труда🫰 .
Поработав в разных сферах и в разных условиях, посмотрев как трудятся люди разных профессий, начинаешь понимать ценность спокойной, "удаленной" работы и достойного, денежного эквивалента этого труда. ☝️
2. Развитие и перспективы в обозримом будущем🏝 .
По моему скромному мнению, пределов развития и так называемого "потолка", у человека выбравшего программирование - нет. Вот нет и все. Кто готов поспорить - жду в комментариях🤓
А есть лишь естественные причины - физические ограничения и ЛЕНЬ.😵
А это значит, что пока руки поднимаются - опускать их мимо клавиатуры, противоестественно!💪
3. Неугасаемый интерес к процессу созидания (написанию кода)🧑💻 .
Один из мощнейших, мотивационных принципов для меня.
Ведь, что может быть прекраснее, чем наблюдать как созданный тобой корабль (условно, конечно же), держится и продолжает плыть в самом современном море, которое еще не исследовано до конца?⛵️
Все это, в совокупности, перевесило мое нежелание (или инерцию мышления и жизни) изучать программирование.
И даже когда (очень часто, столкнувшись с нерешаемой задачей😭 ) мне казалось, что я сделал опрометчиво-глупый выбор - эти принципы помогали преодолеть сомнения (и конечно же задачу, потому что нерешаемых задач НЕТ 💪 ).
😎
#motivation
Мне, 40-летнему человеку, по теории, должно было быть сложно менять профессию.
Тем более, я уже успел получить несколько других и добиться в них немалого успеха.
Так почему же я решился на такую авантюру? (а по другому, мои родные это не называли
Вот некоторые из тех принципов, которые определили пройденный путь:
1. Успех в определенной профессии != достойной зарплате и условиям труда
Поработав в разных сферах и в разных условиях, посмотрев как трудятся люди разных профессий, начинаешь понимать ценность спокойной, "удаленной" работы и достойного, денежного эквивалента этого труда. ☝️
2. Развитие и перспективы в обозримом будущем
По моему скромному мнению, пределов развития и так называемого "потолка", у человека выбравшего программирование - нет. Вот нет и все. Кто готов поспорить - жду в комментариях
А есть лишь естественные причины - физические ограничения и ЛЕНЬ.
А это значит, что пока руки поднимаются - опускать их мимо клавиатуры, противоестественно!
3. Неугасаемый интерес к процессу созидания (написанию кода)
Один из мощнейших, мотивационных принципов для меня.
Ведь, что может быть прекраснее, чем наблюдать как созданный тобой корабль (условно, конечно же), держится и продолжает плыть в самом современном море, которое еще не исследовано до конца?
Все это, в совокупности, перевесило мое нежелание (или инерцию мышления и жизни) изучать программирование.
И даже когда (очень часто, столкнувшись с нерешаемой задачей
#motivation
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👍2
История технологии сегодня — 25 мая
ℹ️ Кто родился в этот день
Джек Стейнбергер (англ. Jack Steinberger; 25 мая 1921, Бад-Киссинген, Германия — 12 декабря 2020, Женева, Швейцария) — американский физик, известный работами по физике элементарных частиц, нобелевский лауреат (1988) за открытие и исследование мюонного нейтрино и антинейтрино.
Пи́тер Зе́еман (нид. Pieter Zeeman; 25 мая 1865, Зоннемайре, Нидерланды — 9 октября 1943, Амстердам) — нидерландский физик, лауреат Нобелевской премии по физике 1902 года (совместно с Хендриком Лоренцем) за открытие и теоретическое объяснение расщепления спектральных линий в магнитном поле (эффекта Зеемана).
Аугу́сто Ульдери́ко Сикаре́ (исп. Augusto Ulderico Cicaré, 25 мая 1937 — 26 января 2022) — аргентинский изобретатель, инженер и авиаконструктор, основатель и первый президент компании Cicaré Helicópteros S.A. Сикаре создал свой первый вертолёт Cicaré CH-1 в 1958 году. CH-1 был первым вертолётом, разработанным в Южной Америке. В 1972 году был представлен третий летательный аппарат — Cicaré CH-3. В конце 1960-х изобретатель разработал 4-тактный V-образный двигатель для автомобилей DKW, протестированный аргентинским гонщиком Хуаном Мануэлем Фанхио. Также была разработана спортивная версия, но банкротство DKW привело к закрытию проекта. Сикаре разработал прототипы вертолётов итальянской фирмы «Heli-Sport» CH-7 Angel и 2-местный CH-7 Kompress, совместно с Деннисом Феттерсом Mini-500, Voyager-500.
🌐 Знаковые события
1939 — первые в стране испытания системы автоматического взлёта и посадки тяжёлого самолёта ТБ-1.
#Biography #Birth_Date #Events #25мая
Джек Стейнбергер (англ. Jack Steinberger; 25 мая 1921, Бад-Киссинген, Германия — 12 декабря 2020, Женева, Швейцария) — американский физик, известный работами по физике элементарных частиц, нобелевский лауреат (1988) за открытие и исследование мюонного нейтрино и антинейтрино.
Пи́тер Зе́еман (нид. Pieter Zeeman; 25 мая 1865, Зоннемайре, Нидерланды — 9 октября 1943, Амстердам) — нидерландский физик, лауреат Нобелевской премии по физике 1902 года (совместно с Хендриком Лоренцем) за открытие и теоретическое объяснение расщепления спектральных линий в магнитном поле (эффекта Зеемана).
Аугу́сто Ульдери́ко Сикаре́ (исп. Augusto Ulderico Cicaré, 25 мая 1937 — 26 января 2022) — аргентинский изобретатель, инженер и авиаконструктор, основатель и первый президент компании Cicaré Helicópteros S.A. Сикаре создал свой первый вертолёт Cicaré CH-1 в 1958 году. CH-1 был первым вертолётом, разработанным в Южной Америке. В 1972 году был представлен третий летательный аппарат — Cicaré CH-3. В конце 1960-х изобретатель разработал 4-тактный V-образный двигатель для автомобилей DKW, протестированный аргентинским гонщиком Хуаном Мануэлем Фанхио. Также была разработана спортивная версия, но банкротство DKW привело к закрытию проекта. Сикаре разработал прототипы вертолётов итальянской фирмы «Heli-Sport» CH-7 Angel и 2-местный CH-7 Kompress, совместно с Деннисом Феттерсом Mini-500, Voyager-500.
1939 — первые в стране испытания системы автоматического взлёта и посадки тяжёлого самолёта ТБ-1.
#Biography #Birth_Date #Events #25мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
[Совет по Java #041]
Тема: Integer кэширует значения от -128 до 127.
Проблема: JVM кэширует объекты
Решение: Всегда сравнивайте объекты
Объяснение: Кэш
Оператор
Для смешанного сравнения
#Java #советы
Тема: Integer кэширует значения от -128 до 127.
Проблема: JVM кэширует объекты
Integer для небольшого диапазона значений (по умолчанию от -128 до 127). При автоупаковке (autoboxing) или вызове Integer.valueOf() для числа в этом диапазоне возвращается один и тот же объект из кэша. Для чисел вне диапазона каждый раз создается новый объект. Использование оператора == для сравнения Integer проверяет равенство ссылок, а не значений.Решение: Всегда сравнивайте объекты
Integer, Long, Short, Byte, Character через метод equals() или используйте примитивные типы (int). Для безопасного сравнения с возможным null применяйте Objects.equals(a, b). Кэш можно расширить параметром -XX:AutoBoxCacheMax=size, но это не решает концептуальной проблемы. Для Long кэш работает только для значений от -128 до 127, для Character — от 0 до 127.public class IntegerCache {
public static void main(String[] args) {
//В пределах кэша (-128..127)
Integer a1 = 100;
Integer b1 = 100;
System.out.println("100 == 100: " + (a1 == b1)); // true (один объект)
System.out.println("100 equals 100: " + a1.equals(b1)); // true
//Вне кэша
Integer a2 = 200;
Integer b2 = 200;
System.out.println("200 == 200: " + (a2 == b2)); // false (разные объекты!)
System.out.println("200 equals 200: " + a2.equals(b2)); // true
//Разные способы создания
Integer a3 = Integer.valueOf(127); // из кэша
Integer b3 = new Integer(127); // новый объект (deprecated)
System.out.println("valueOf(127) == new Integer(127): " + (a3 == b3)); // false
//Опасность в коллекциях
var map = new java.util.HashMap<Integer, String>();
map.put(200, "value");
System.out.println("map.get(200): " + map.get(200)); // работает, т.к. внутри equals
//Правильное сравнение
Integer x = 300;
Integer y = 300;
if (x.equals(y)) {
System.out.println("300 equals 300 — корректно");
}
//null-safe сравнение
Integer nullable = null;
System.out.println("Objects.equals: " + Objects.equals(nullable, 300));
}
}Объяснение: Кэш
Integer реализован в методе Integer.valueOf() и используется при автоупаковке. Его размер можно настроить, но полагаться на кэш — плохая практика. Оператор
== для объектов сравнивает ссылки, и для чисел вне диапазона кэша они гарантированно разные. Проблема усугубляется тем, что код работает в разработке (где числа обычно маленькие) и ломается в production (где диапазон шире). equals() сравнивает значения и всегда работает корректно. Для смешанного сравнения
Integer и int происходит распаковка (unboxing), и == работает правильно: Integer a = 200; int b = 200; a == b будет true, потому что a распаковывается в int. Но для единообразия всегда используйте equals().#Java #советы
👍5
Что выведет код?
#Tasks
public class Task250526 {
public static void main(String[] args) {
Short a = 100;
Short b = 100;
Short c = 200;
Short d = 200;
System.out.println(a == b);
System.out.println(c == d);
System.out.println(c.equals(d));
}
}#Tasks
👍3
Варианты ответа:
Anonymous Quiz
41%
true true true
47%
true false true
12%
false false true
0%
false true false
👍4
Что такое ThreadFactory? 🤓
Ответ:
ThreadFactory — это интерфейс для создания новых потоков с возможностью кастомизации.
Единственный метод: Thread newThread(Runnable r). Используется в ExecutorService (например, Executors.newFixedThreadPool(10, myThreadFactory)).
Позволяет задавать: имена потоков (для упрощения отладки), приоритеты, демонический статус, UncaughtExceptionHandler.
Хорошая практика — создавать потоки с понятными именами (например, "db-pool-%d"). Утилита Executors.defaultThreadFactory() возвращает стандартную фабрику.
#собеседование
Ответ:
ThreadFactory — это интерфейс для создания новых потоков с возможностью кастомизации.
Единственный метод: Thread newThread(Runnable r). Используется в ExecutorService (например, Executors.newFixedThreadPool(10, myThreadFactory)).
Позволяет задавать: имена потоков (для упрощения отладки), приоритеты, демонический статус, UncaughtExceptionHandler.
Хорошая практика — создавать потоки с понятными именами (например, "db-pool-%d"). Утилита Executors.defaultThreadFactory() возвращает стандартную фабрику.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 26 мая
ℹ️ Кто родился в этот день
Бори́с Серге́евич Петропа́вловский (14 (26) мая 1898, Курск — 6 ноября 1933, Ленинград) — российский и советский военный инженер-артиллерист, участник Первой мировой и Гражданской войн, один из организаторов разработок ракетной техники в СССР, руководитель Газодинамической лаборатории, главный инженер Ленинградского отделения Реактивного научно-исследовательского института (РНИИ). Именем Б. С. Петропавловского был назван кратер на обратной стороне Луны.
🌐 Знаковые события
1868 — Альфред Нобель подал заявку на американский патент на изобретение динамита.
#Biography #Birth_Date #Events #26мая
Бори́с Серге́евич Петропа́вловский (14 (26) мая 1898, Курск — 6 ноября 1933, Ленинград) — российский и советский военный инженер-артиллерист, участник Первой мировой и Гражданской войн, один из организаторов разработок ракетной техники в СССР, руководитель Газодинамической лаборатории, главный инженер Ленинградского отделения Реактивного научно-исследовательского института (РНИИ). Именем Б. С. Петропавловского был назван кратер на обратной стороне Луны.
1868 — Альфред Нобель подал заявку на американский патент на изобретение динамита.
#Biography #Birth_Date #Events #26мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Раздел 9. Исключения, логирование, отладка
Глава 2. Логирование (Logging)
MDC (Mapped Diagnostic Context) – привязка контекстной информации к логам
В многопоточном серверном приложении один и тот же логгер обрабатывает запросы от множества клиентов параллельно. Стандартный вывод логов представляет собой линейную последовательность сообщений от разных потоков, где запросы перемешаны хаотично. Без дополнительного контекста невозможно отследить, какие сообщения относятся к конкретному пользователю или HTTP-запросу.
Рассмотрим типичный лог без MDC:
По имени потока можно различить запросы, но имена потоков переиспользуются пулом и не несут бизнес-семантики. Для анализа проблемы конкретного пользователя или запроса требуется ручной поиск по временным меткам и косвенным признакам.
Архитектура MDC
MDC — это карта ключ-значение, привязанная к текущему потоку выполнения через
Основные операции:
Контекст MDC автоматически подставляется в лог-сообщения через conversion specifier
Базовое использование
Конфигурация Logback для вывода MDC:
Результат:
Все сообщения, выведенные в рамках одного запроса, содержат идентификаторы пользователя и заказа. Это позволяет фильтровать логи grep-ом или в системах агрегации по конкретным значениям MDC.
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
Глава 2. Логирование (Logging)
MDC (Mapped Diagnostic Context) – привязка контекстной информации к логам
В многопоточном серверном приложении один и тот же логгер обрабатывает запросы от множества клиентов параллельно. Стандартный вывод логов представляет собой линейную последовательность сообщений от разных потоков, где запросы перемешаны хаотично. Без дополнительного контекста невозможно отследить, какие сообщения относятся к конкретному пользователю или HTTP-запросу.
Рассмотрим типичный лог без MDC:
2024-01-15 10:23:14 [http-nio-8080-exec-3] INFO OrderService - Processing order
2024-01-15 10:23:14 [http-nio-8080-exec-1] INFO PaymentService - Charging card
2024-01-15 10:23:14 [http-nio-8080-exec-3] WARN InventoryService - Low stock
2024-01-15 10:23:15 [http-nio-8080-exec-2] ERROR OrderService - Payment failed
По имени потока можно различить запросы, но имена потоков переиспользуются пулом и не несут бизнес-семантики. Для анализа проблемы конкретного пользователя или запроса требуется ручной поиск по временным меткам и косвенным признакам.
Архитектура MDC
MDC — это карта ключ-значение, привязанная к текущему потоку выполнения через
ThreadLocal. SLF4J предоставляет статический API класса org.slf4j.MDC, который делегирует реализации (Logback или Log4j2) фактическое хранение контекста. Каждый поток имеет собственную изолированную копию MDC, что гарантирует отсутствие перекрестного загрязнения между параллельными запросами.Основные операции:
MDC.put(String key, String value) — добавляет пару ключ-значение в контекст текущего потокаMDC.get(String key) — извлекает значение по ключуMDC.remove(String key) — удаляет конкретный ключMDC.clear() — очищает весь контекст текущего потокаКонтекст MDC автоматически подставляется в лог-сообщения через conversion specifier
%X{key} в PatternLayout.Базовое использование
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
public class OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
public void processOrder(String orderId, String userId) {
// Установка контекста в начале операции
MDC.put("orderId", orderId);
MDC.put("userId", userId);
MDC.put("operation", "processOrder");
try {
logger.info("Starting order processing");
validateOrder(orderId);
chargePayment(orderId, userId);
updateInventory(orderId);
logger.info("Order processing completed");
} catch (Exception e) {
logger.error("Order processing failed", e);
throw e;
} finally {
// Обязательная очистка контекста
MDC.clear();
}
}
}
Конфигурация Logback для вывода MDC:
<property name="LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%X{userId}] [%X{orderId}] - %msg%n"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
Результат:
2024-01-15 10:23:14.123 [http-nio-8080-exec-3] INFO OrderService [user-42] [order-789] - Starting order processing
2024-01-15 10:23:14.145 [http-nio-8080-exec-3] INFO PaymentService [user-42] [order-789] - Charging payment
2024-01-15 10:23:14.167 [http-nio-8080-exec-3] INFO OrderService [user-42] [order-789] - Order processing completed
Все сообщения, выведенные в рамках одного запроса, содержат идентификаторы пользователя и заказа. Это позволяет фильтровать логи grep-ом или в системах агрегации по конкретным значениям MDC.
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍1
MDC в веб-приложении: Servlet Filter
В веб-приложении контекст запроса устанавливается в фильтре сервлетов и очищается при завершении обработки. Это гарантирует, что все компоненты, участвующие в обработке запроса — контроллеры, сервисы, репозитории — имеют доступ к единому контексту без явной передачи параметров через сигнатуры методов.
Ключевой момент:
Конфигурация Logback с MDC:
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
В веб-приложении контекст запроса устанавливается в фильтре сервлетов и очищается при завершении обработки. Это гарантирует, что все компоненты, участвующие в обработке запроса — контроллеры, сервисы, репозитории — имеют доступ к единому контексту без явной передачи параметров через сигнатуры методов.
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.UUID;
@Component
public class LoggingContextFilter extends OncePerRequestFilter {
private static final String REQUEST_ID_HEADER = "X-Request-Id";
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// Генерация или извлечение идентификатора запроса
String requestId = request.getHeader(REQUEST_ID_HEADER);
if (requestId == null || requestId.isBlank()) {
requestId = UUID.randomUUID().toString();
}
// Извлечение контекста аутентификации
String userId = extractUserId(request);
String sessionId = request.getSession(false) != null ?
request.getSession().getId() : "anonymous";
// Установка MDC
MDC.put("requestId", requestId);
MDC.put("userId", userId != null ? userId : "anonymous");
MDC.put("sessionId", sessionId);
MDC.put("method", request.getMethod());
MDC.put("uri", request.getRequestURI());
// Проброс requestId в ответ для клиентской трассировки
response.setHeader(REQUEST_ID_HEADER, requestId);
try {
filterChain.doFilter(request, response);
} finally {
// Очистка обязательна, иначе поток из пула вернется с загрязненным контекстом
MDC.clear();
}
}
private String extractUserId(HttpServletRequest request) {
// Извлечение из SecurityContext или токена
return SecurityContextHolder.getContext().getAuthentication() != null ?
SecurityContextHolder.getContext().getAuthentication().getName() : null;
}
}
Ключевой момент:
MDC.clear() находится в блоке finally, что гарантирует очистку даже при исключении. Без этого поток из пула вернется с загрязненным MDC, и следующий запрос, обработанный этим потоком, унаследует чужой контекст.Конфигурация Logback с MDC:
<property name="LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%X{requestId}] [%X{userId}] [%X{method} %X{uri}] - %msg%n"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍3