All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.rxmicro.logger.jul.PatternFormatter Maven / Gradle / Ivy

Go to download

The module for logging important events during the work of microservices that is integrated to the RxMicro framework.

The newest version!
/*
 * Copyright (c) 2020. https://rxmicro.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.rxmicro.logger.jul;

import io.rxmicro.common.util.Formats;
import io.rxmicro.logger.internal.jul.config.adapter.pattern.PatternFormatterBiConsumerParser;
import io.rxmicro.logger.internal.message.IgnoreLineSeparatorMessageBuilder;
import io.rxmicro.logger.internal.message.MessageBuilder;
import io.rxmicro.logger.internal.message.ReplaceLineSeparatorMessageBuilder;

import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;

import static io.rxmicro.logger.internal.jul.InternalLoggerHelper.logInternal;
import static java.util.logging.LogManager.getLogManager;

/**
 * This class supports conversion specifiers that can be used as format control expressions.
 *
 * 

* Each conversion specifier starts with a percent sign {@code '%'} and is followed by optional format modifiers, * a conversion word and optional parameters between braces. * The conversion word controls the data field to convert, e.g. logger name or date format. * *

* Configuration: * By default each {@link PatternFormatter} is initialized using the following {@link LogManager} configuration properties. * If properties are not defined (or have invalid values) then the specified default values are used. *

    *
  • * {@code io.rxmicro.logger.jul.PatternFormatter.pattern} specifies the pattern for the logged messages * (defaults to {@value #DEFAULT_PATTERN}). *
  • *
  • * {@code io.rxmicro.logger.jul.PatternFormatter.singleLine} indicates that all logged messages must be formatted as single line, * i.e. the {@code '\r\n'} or {@code '\n'} characters must be replaced. (defaults to {@code false}). *
  • *
  • * {@code io.rxmicro.logger.jul.PatternFormatter.replacement} specifies the string that must be used as replacement for * the {@code '\r\n'} or {@code '\n'} characters. * This parameter is ignored if {@code io.rxmicro.logger.jul.PatternFormatter.singleLine} is not {@code true}. * If this parameter is {@value #IGNORE_REPLACEMENT}, than the {@code '\r\n'} or {@code '\n'} characters will be ignored. * (defaults to platform specific strings: * {@code "\\r\\n"} for Windows, {@code "\\n"} for Linux and Osx) *
  • *
* *

* The {@link PatternFormatter} supports the following conversion specifiers: *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Conversion specifiersDescription
* c{length}
* lo{length}
* logger{length}
*
* Outputs the name of the logger at the origin of the logging event. *

* This conversion specifier takes a string as its first and only option. * Currently supported only one of the following options: {short}, {0}, {full}. * {short} is synonym for {0} option. * If no option defined this conversion specifier uses {full} option. *

* The following table describes option usage results: *

* * * * * * * * * * * * * * * * * * * * * * * * * *
Conversion specifierLogger nameResult
%loggermainPackage.sub.sample.BarmainPackage.sub.sample.Bar
%logger{full}mainPackage.sub.sample.BarmainPackage.sub.sample.Bar
%logger{short}mainPackage.sub.sample.BarBar
%logger{0}mainPackage.sub.sample.BarBar
*
* C{length}
* class{length}
*
* Outputs the fully-qualified class name of the caller issuing the logging request. *

* This conversion specifier takes a string as its first and only option. * Currently supported only one of the following options: {short}, {0}, {full}. * {short} is synonym for {0} option. * If no option defined this conversion specifier uses {full} option. *

* The following table describes option usage results. *

* * * * * * * * * * * * * * * * * * * * * * * * * *
Conversion specifierClass nameResult
%loggermainPackage.sub.sample.BarmainPackage.sub.sample.Bar
%logger{full}mainPackage.sub.sample.BarmainPackage.sub.sample.Bar
%logger{short}mainPackage.sub.sample.BarBar
%logger{0}mainPackage.sub.sample.BarBar
*

* Generating the caller class information is not particularly fast. * Thus, its use should be avoided unless execution speed is not an issue. *

* d{pattern}
* date{pattern}
* d{pattern, timezone}
* date{pattern, timezone}
*
* Used to output the date of the logging event. *

* The date conversion word admits a pattern string as a parameter. * The pattern syntax is compatible with the format accepted by {@link java.time.format.DateTimeFormatter}. * If {@code timezone} is specified, this conversion specifier uses {@link java.time.ZoneId#of(String)} method to parse it, * so timezone syntax must be compatible with zone id format. *

* Here are some sample parameter values: *

* * * * * * * * * * * * * * * * * * * * *
Conversion patternResult
%date{@code 2020-01-02 03:04:05.123}
%date{yyyy-MM-dd}{@code 2020-01-02}
%date{HH:mm:ss.SSS}{@code 03:04:05.123}
%date{, UTC}{@code 2020-01-02 03:04:05.123}
*

* If pattern is missing (For example: {@code %d}, {@code %date}, {@code %date{, UTC}}, the default pattern will be used: * {@value io.rxmicro.logger.internal.jul.config.adapter.pattern.consumers.DateTimeOfLoggingEventBiConsumer#DEFAULT_PATTERN} *

* F
* file
*
* Outputs the file name of the Java source file where the logging request was issued. *

* Generating the file information is not particularly fast. * Thus, its use should be avoided unless execution speed is not an issue. *

* L
* line
*
* Outputs the line number from where the logging request was issued. *

* Generating the line number information is not particularly fast. * Thus, its use should be avoided unless execution speed is not an issue. *

* m
* mes
* message
*
* Outputs the application-supplied message associated with the logging event. *
* M
* method
*
* Outputs the method name where the logging request was issued. *

* Generating the method name is not particularly fast. * Thus, its use should be avoided unless execution speed is not an issue. *

* n
*
* Outputs the platform dependent line separator character or characters. *

* This conversion word offers practically the same performance as using non-portable line separator strings * such as "\n", or "\r\n". Thus, it is the preferred way of specifying a line separator. *

* p
* le
* level
*
* Outputs the level of the logging event. *
* r
* relative
*
* Outputs the number of milliseconds elapsed since the start of the application until the creation of the logging event. *
* t
* thread
*
* Outputs the name of the thread that generated the logging event. *
* id
* rid
* request-id
* request_id
* requestId
*
* Outputs the request id if specified. *
* * * @author nedis * @link https://logback.qos.ch/manual/layouts.html#conversionWord * @since 0.7 */ public final class PatternFormatter extends Formatter { /** * Default pattern. */ public static final String DEFAULT_PATTERN = "%d{yyyy-MM-dd HH:mm:ss.SSS} [%p] %c: %m%n"; /** * Ignore replacement constant. */ public static final String IGNORE_REPLACEMENT = "ignore"; private static final String FULL_CLASS_NAME = PatternFormatter.class.getName(); private final List> biConsumers; private final Supplier messageBuilderSupplier; private static String resolvePattern() { return Optional.ofNullable(getLogManager().getProperty(Formats.format("?.pattern", FULL_CLASS_NAME))) .filter(value -> !value.isEmpty()) .orElse(DEFAULT_PATTERN); } private static boolean isSingleLineEnabled() { return Boolean.parseBoolean(getLogManager().getProperty(Formats.format("?.singleLine", FULL_CLASS_NAME))); } private static String resolveReplacement() { return getLogManager().getProperty(Formats.format("?.replacement", FULL_CLASS_NAME)); } /** * Creates an instance of {@link PatternFormatter} class with the specified pattern. * * @param pattern the specified pattern. * @param singleLineEnabled flag that indicates that current {@link PatternFormatter} must format message as single line. * @param replacement the specified replacement or {@code null} if must be default value */ public PatternFormatter(final String pattern, final boolean singleLineEnabled, final String replacement) { List> biConsumers; try { biConsumers = new PatternFormatterBiConsumerParser().parse(pattern, singleLineEnabled); } catch (final PatternFormatterParseException ex) { logInternal( Level.SEVERE, "The '?' pattern is invalid: ?. Set '?' as pattern for all log messages!", pattern, ex.getMessage(), DEFAULT_PATTERN ); biConsumers = new PatternFormatterBiConsumerParser().parse(DEFAULT_PATTERN, singleLineEnabled); } this.biConsumers = biConsumers; if (singleLineEnabled) { if (replacement == null) { // Default replacement this.messageBuilderSupplier = ReplaceLineSeparatorMessageBuilder::new; } else if (IGNORE_REPLACEMENT.equals(replacement)) { this.messageBuilderSupplier = IgnoreLineSeparatorMessageBuilder::new; } else { this.messageBuilderSupplier = () -> new ReplaceLineSeparatorMessageBuilder(replacement); } } else { this.messageBuilderSupplier = MessageBuilder::new; } } /** * Creates an instance of {@link PatternFormatter} class with the {@code pattern} and {@code singleLineEnabled} parameters * resolved from properties file. * *

* If configuration file contains the following property: *


     * io.rxmicro.logger.jul.PatternFormatter.pattern=${CUSTOM_PATTERN}
     * 
* then {@code ${CUSTOM_PATTERN}} will be used as pattern instead of default one: '{@value #DEFAULT_PATTERN}' * *

* If configuration file contains the following property: * {@code io.rxmicro.logger.jul.PatternFormatter.singleLine=true} * then the current instance formats all messages as single line, i.e. replaces the {@code '\r\n'} or {@code '\n'} * characters by {@code "\\n"} for Linux and Osx or {@code "\\r\\n"} for Windows string. * *

* If configuration file contains the following property: * {@code io.rxmicro.logger.jul.PatternFormatter.replacement=ANY_PROVIDED_STRING} * then the provided string is used as replacement for the {@code '\r\n'} or {@code '\n'} characters. */ public PatternFormatter() { this(resolvePattern(), isSingleLineEnabled(), resolveReplacement()); } @Override public String format(final LogRecord logRecord) { final MessageBuilder messageBuilder = messageBuilderSupplier.get(); for (final BiConsumer biConsumer : biConsumers) { biConsumer.accept(messageBuilder, logRecord); } return messageBuilder.build(); } @Override public String toString() { return "PatternFormatter{" + "biConsumers=" + biConsumers + '}'; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy