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

org.apache.ignite.logger.log4j2.Log4J2Logger Maven / Gradle / Ivy

Go to download

Apache Ignite® is a Distributed Database For High-Performance Computing With In-Memory Speed.

There is a newer version: 2.16.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.ignite.logger.log4j2;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.UUID;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteLogger;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.typedef.C1;
import org.apache.ignite.internal.util.typedef.internal.A;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteClosure;
import org.apache.ignite.logger.LoggerNodeIdAware;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.appender.FileAppender;
import org.apache.logging.log4j.core.appender.RollingFileAppender;
import org.apache.logging.log4j.core.appender.routing.RoutingAppender;
import org.apache.logging.log4j.core.config.AppenderControl;
import org.apache.logging.log4j.core.config.AppenderRef;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.jetbrains.annotations.Nullable;

import static org.apache.ignite.IgniteSystemProperties.IGNITE_CONSOLE_APPENDER;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_QUIET;

/**
 * Log4j2-based implementation for logging. This logger should be used
 * by loaders that have prefer log4j2-based logging.
 * 

* Here is a typical example of configuring log4j2 logger in Ignite configuration file: *

 *      <property name="gridLogger">
 *          <bean class="org.apache.ignite.logger.log4j2.Log4J2Logger">
 *              <constructor-arg type="java.lang.String" value="config/ignite-log4j2.xml"/>
 *          </bean>
 *      </property>
 * 
* and from your code: *
 *      IgniteConfiguration cfg = new IgniteConfiguration();
 *      ...
 *      URL xml = U.resolveIgniteUrl("config/custom-log4j2.xml");
 *      IgniteLogger log = new Log4J2Logger(xml);
 *      ...
 *      cfg.setGridLogger(log);
 * 
* * Please take a look at Apache Log4j 2 * for additional information. *

* It's recommended to use Ignite logger injection instead of using/instantiating * logger in your task/job code. See {@link org.apache.ignite.resources.LoggerResource} annotation about logger * injection. */ public class Log4J2Logger implements IgniteLogger, LoggerNodeIdAware { /** */ private static final String NODE_ID = "nodeId"; /** */ private static final String CONSOLE_APPENDER = "autoConfiguredIgniteConsoleAppender"; /** */ private static volatile boolean inited; /** */ private static volatile boolean quiet0; /** */ private static final Object mux = new Object(); /** Logger implementation. */ @GridToStringExclude @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized") private Logger impl; /** Auto added at verbose mode console logger (nullable). */ @GridToStringExclude @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized") private Logger consoleLog; /** Quiet flag. */ private final boolean quiet; /** Node ID. */ private volatile UUID nodeId; /** * Creates new logger with given implementation. * * @param impl Log4j implementation to use. * @param consoleLog Cosole logger (optional). */ private Log4J2Logger(final Logger impl, @Nullable final Logger consoleLog) { assert impl != null; this.impl = impl; this.consoleLog = consoleLog; quiet = quiet0; } /** * Creates new logger with given configuration {@code path}. * * @param path Path to log4j configuration XML file. * @throws IgniteCheckedException Thrown in case logger can't be created. */ public Log4J2Logger(String path) throws IgniteCheckedException { if (path == null) throw new IgniteCheckedException("Configuration XML file for Log4j must be specified."); final URL cfgUrl = U.resolveIgniteUrl(path); if (cfgUrl == null) throw new IgniteCheckedException("Log4j configuration path was not found: " + path); addConsoleAppenderIfNeeded(new C1() { @Override public Logger apply(Boolean init) { if (init) Configurator.initialize(LogManager.ROOT_LOGGER_NAME, cfgUrl.toString()); return (Logger)LogManager.getRootLogger(); } }); quiet = quiet0; } /** * Creates new logger with given configuration {@code cfgFile}. * * @param cfgFile Log4j configuration XML file. * @throws IgniteCheckedException Thrown in case logger can't be created. */ public Log4J2Logger(File cfgFile) throws IgniteCheckedException { if (cfgFile == null) throw new IgniteCheckedException("Configuration XML file for Log4j must be specified."); if (!cfgFile.exists() || cfgFile.isDirectory()) throw new IgniteCheckedException("Log4j2 configuration path was not found or is a directory: " + cfgFile); final String path = cfgFile.getAbsolutePath(); addConsoleAppenderIfNeeded(new C1() { @Override public Logger apply(Boolean init) { if (init) Configurator.initialize(LogManager.ROOT_LOGGER_NAME, path); return (Logger)LogManager.getRootLogger(); } }); quiet = quiet0; } /** * Creates new logger with given configuration {@code cfgUrl}. * * @param cfgUrl URL for Log4j configuration XML file. * @throws IgniteCheckedException Thrown in case logger can't be created. */ public Log4J2Logger(final URL cfgUrl) throws IgniteCheckedException { if (cfgUrl == null) throw new IgniteCheckedException("Configuration XML file for Log4j must be specified."); addConsoleAppenderIfNeeded(new C1() { @Override public Logger apply(Boolean init) { if (init) Configurator.initialize(LogManager.ROOT_LOGGER_NAME, cfgUrl.toString()); return (Logger)LogManager.getRootLogger(); } }); quiet = quiet0; } /** * Sets level for internal log4j implementation. * * @param level Log level to set. */ public void setLevel(Level level) { LoggerContext ctx = (LoggerContext)LogManager.getContext(false); Configuration conf = ctx.getConfiguration(); conf.getLoggerConfig(impl.getName()).setLevel(level); ctx.updateLoggers(conf); } /** {@inheritDoc} */ @Nullable @Override public String fileName() { for (Logger log = impl; log != null; log = log.getParent()) { for (Appender a : log.getAppenders().values()) { if (a instanceof FileAppender) return ((FileAppender)a).getFileName(); if (a instanceof RollingFileAppender) return ((RollingFileAppender)a).getFileName(); if (a instanceof RoutingAppender) { try { RoutingAppender routing = (RoutingAppender)a; Field appsFiled = routing.getClass().getDeclaredField("appenders"); appsFiled.setAccessible(true); Map appenders = (Map)appsFiled.get(routing); for (AppenderControl control : appenders.values()) { Appender innerApp = control.getAppender(); if (innerApp instanceof FileAppender) return normilize(((FileAppender)innerApp).getFileName()); if (innerApp instanceof RollingFileAppender) return normilize(((RollingFileAppender)innerApp).getFileName()); } } catch (IllegalAccessException | NoSuchFieldException e) { error("Failed to get file name (was the implementation of log4j2 changed?).", e); } } } } return null; } /** * Normalizes given path for windows. * Log4j2 doesn't replace unix directory delimiters which used at 'fileName' to windows. * * @param path Path. * @return Normalized path. */ private String normilize(String path) { if (!U.isWindows()) return path; return path.replace('/', File.separatorChar); } /** * Adds console appender when needed with some default logging settings. * * @param initLogClo Optional log implementation init closure. */ private void addConsoleAppenderIfNeeded(@Nullable IgniteClosure initLogClo) { if (inited) { // Do not init. impl = initLogClo.apply(false); return; } synchronized (mux) { if (inited) { // Do not init. impl = initLogClo.apply(false); return; } // Init logger impl. impl = initLogClo.apply(true); boolean quiet = Boolean.valueOf(System.getProperty(IGNITE_QUIET, "true")); boolean consoleAppenderFound = false; Logger rootLogger = null; for (Logger log = impl; log != null; ) { if (!consoleAppenderFound) { for (Appender appender : log.getAppenders().values()) { if (appender instanceof ConsoleAppender) { if ("CONSOLE_ERR".equals(appender.getName())) continue; consoleAppenderFound = true; break; } } } if (log.getParent() == null) { rootLogger = log; break; } else log = log.getParent(); } if (consoleAppenderFound && quiet) // User configured console appender, but log is quiet. quiet = false; if (!consoleAppenderFound && !quiet && Boolean.valueOf(System.getProperty(IGNITE_CONSOLE_APPENDER, "true"))) { // Console appender not found => we've looked through all categories up to root. assert rootLogger != null; // User launched ignite in verbose mode and did not add console appender with INFO level // to configuration and did not set IGNITE_CONSOLE_APPENDER to false. consoleLog = createConsoleLogger(); } quiet0 = quiet; inited = true; } } /** * Creates console appender with some reasonable default logging settings. * * @return Logger with auto configured console appender. */ public static Logger createConsoleLogger() { LoggerContext ctx = (LoggerContext)LogManager.getContext(true); Configuration cfg = ctx.getConfiguration(); PatternLayout.Builder builder = PatternLayout.newBuilder(); builder .withPattern("%d{ISO8601}][%-5p][%t][%c{1}] %m%n") .withCharset(Charset.defaultCharset()) .withAlwaysWriteExceptions(false) .withNoConsoleNoAnsi(false); PatternLayout layout = builder.build(); ConsoleAppender.Builder consoleAppenderBuilder = ConsoleAppender.newBuilder(); consoleAppenderBuilder .withName(CONSOLE_APPENDER) .withLayout(layout); ConsoleAppender consoleApp = consoleAppenderBuilder.build(); consoleApp.start(); AppenderRef ref = AppenderRef.createAppenderRef(CONSOLE_APPENDER, Level.TRACE, null); AppenderRef[] refs = {ref}; LoggerConfig logCfg = LoggerConfig.createLogger(false, Level.INFO, LogManager.ROOT_LOGGER_NAME, "", refs, null, null, null); logCfg.addAppender(consoleApp, null, null); cfg.addAppender(consoleApp); cfg.addLogger(LogManager.ROOT_LOGGER_NAME, logCfg); ctx.updateLoggers(cfg); return (Logger)LogManager.getContext().getLogger(LogManager.ROOT_LOGGER_NAME); } /** {@inheritDoc} */ @Override public void setNodeId(UUID nodeId) { A.notNull(nodeId, "nodeId"); this.nodeId = nodeId; // Set nodeId as system variable to be used at configuration. System.setProperty(NODE_ID, U.id8(nodeId)); ((LoggerContext)LogManager.getContext(false)).reconfigure(); } /** {@inheritDoc} */ @Override public UUID getNodeId() { return nodeId; } /** * Gets {@link IgniteLogger} wrapper around log4j logger for the given * category. If category is {@code null}, then root logger is returned. If * category is an instance of {@link Class} then {@code (Class)ctgr).getName()} * is used as category name. * * @param ctgr {@inheritDoc} * @return {@link IgniteLogger} wrapper around log4j logger. */ @Override public Log4J2Logger getLogger(Object ctgr) { if (ctgr == null) return new Log4J2Logger((Logger)LogManager.getRootLogger(), consoleLog == null ? null : (Logger)LogManager.getContext().getLogger("")); if (ctgr instanceof Class) { String name = ((Class)ctgr).getName(); return new Log4J2Logger((Logger)LogManager.getLogger(name), consoleLog == null ? null : (Logger)LogManager.getContext().getLogger(name)); } String name = ctgr.toString(); return new Log4J2Logger((Logger)LogManager.getLogger(name), consoleLog == null ? null : (Logger)LogManager.getContext().getLogger(name)); } /** {@inheritDoc} */ @Override public void trace(String msg) { if (!isTraceEnabled()) warning("Logging at TRACE level without checking if TRACE level is enabled: " + msg); impl.trace(msg); if (consoleLog != null) consoleLog.trace(msg); } /** {@inheritDoc} */ @Override public void debug(String msg) { if (!isDebugEnabled()) warning("Logging at DEBUG level without checking if DEBUG level is enabled: " + msg); impl.debug(msg); if (consoleLog != null) consoleLog.debug(msg); } /** {@inheritDoc} */ @Override public void info(String msg) { if (!isInfoEnabled()) warning("Logging at INFO level without checking if INFO level is enabled: " + msg); impl.info(msg); if (consoleLog != null) consoleLog.info(msg); } /** {@inheritDoc} */ @Override public void warning(String msg) { impl.warn(msg); if (consoleLog != null) consoleLog.warn(msg); } /** {@inheritDoc} */ @Override public void warning(String msg, @Nullable Throwable e) { impl.warn(msg, e); if (consoleLog != null) consoleLog.warn(msg, e); } /** {@inheritDoc} */ @Override public void error(String msg) { impl.error(msg); if (consoleLog != null) consoleLog.error(msg); } /** {@inheritDoc} */ @Override public void error(String msg, @Nullable Throwable e) { impl.error(msg, e); if (consoleLog != null) consoleLog.error(msg, e); } /** {@inheritDoc} */ @Override public boolean isTraceEnabled() { return impl.isTraceEnabled() || (consoleLog != null && consoleLog.isTraceEnabled()); } /** {@inheritDoc} */ @Override public boolean isDebugEnabled() { return impl.isDebugEnabled() || (consoleLog != null && consoleLog.isDebugEnabled()); } /** {@inheritDoc} */ @Override public boolean isInfoEnabled() { return impl.isInfoEnabled() || (consoleLog != null && consoleLog.isInfoEnabled()); } /** {@inheritDoc} */ @Override public boolean isQuiet() { return quiet; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(Log4J2Logger.class, this); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy