| /* |
| * 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.geode.internal.logging; |
| |
| import static java.lang.System.lineSeparator; |
| |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.text.BreakIterator; |
| import java.text.DateFormat; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.List; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| import java.util.logging.Handler; |
| import java.util.logging.Level; |
| |
| import org.apache.geode.LogWriter; |
| import org.apache.geode.annotations.internal.MakeNotStatic; |
| import org.apache.geode.i18n.LogWriterI18n; |
| import org.apache.geode.i18n.StringId; |
| import org.apache.geode.internal.Assert; |
| import org.apache.geode.internal.process.StartupStatusListener; |
| import org.apache.geode.logging.internal.executors.LoggingThread; |
| |
| /** |
| * Abstract implementation of {@link InternalLogWriter}. Each logger has a level and it will only |
| * print messages whose level is greater than or equal to the logger's level. The supported logger |
| * level constants, in ascending order, are: |
| * <ol> |
| * <li>{@link #ALL_LEVEL} |
| * <li>{@link #FINEST_LEVEL} |
| * <li>{@link #FINER_LEVEL} |
| * <li>{@link #FINE_LEVEL} |
| * <li>{@link #CONFIG_LEVEL} |
| * <li>{@link #INFO_LEVEL} |
| * <li>{@link #WARNING_LEVEL} |
| * <li>{@link #ERROR_LEVEL} |
| * <li>{@link #SEVERE_LEVEL} |
| * <li>{@link #NONE_LEVEL} |
| * </ol> |
| * <p> |
| * Subclasses must implement: |
| * <ol> |
| * <li>{@link #getLogWriterLevel} |
| * <li>{@link #put(int, String, Throwable)} |
| * <li>{@link #put(int, StringId, Object[], Throwable)} |
| * </ol> |
| * |
| * @deprecated Please use Log4J2 instead. |
| */ |
| @Deprecated |
| public abstract class LogWriterImpl implements InternalLogWriter { |
| |
| /** |
| * A bit mask to remove any potential flags added to the msgLevel. Intended to be used in |
| * {@link #getRealLogLevel}. |
| */ |
| private static final int LOGGING_FLAGS_MASK = 0x00FFFFFF; |
| |
| /** |
| * A flag to indicate the {@link SecurityLogWriter#SECURITY_PREFIX} should be appended to the log |
| * level. |
| */ |
| private static final int SECURITY_LOGGING_FLAG = 0x40000000; |
| |
| static { |
| Assert.assertTrue(ALL_LEVEL == Level.ALL.intValue()); |
| Assert.assertTrue(NONE_LEVEL == Level.OFF.intValue()); |
| Assert.assertTrue(FINEST_LEVEL == Level.FINEST.intValue()); |
| Assert.assertTrue(FINER_LEVEL == Level.FINER.intValue()); |
| Assert.assertTrue(FINE_LEVEL == Level.FINE.intValue()); |
| Assert.assertTrue(CONFIG_LEVEL == Level.CONFIG.intValue()); |
| Assert.assertTrue(INFO_LEVEL == Level.INFO.intValue()); |
| Assert.assertTrue(WARNING_LEVEL == Level.WARNING.intValue()); |
| Assert.assertTrue(SEVERE_LEVEL == Level.SEVERE.intValue()); |
| int logLevels = FINEST_LEVEL | FINER_LEVEL | FINE_LEVEL | CONFIG_LEVEL | INFO_LEVEL |
| | WARNING_LEVEL | SEVERE_LEVEL; |
| Assert.assertTrue(logLevels == (logLevels & LOGGING_FLAGS_MASK)); |
| Assert.assertTrue(0 == (logLevels & SECURITY_LOGGING_FLAG)); |
| } |
| |
| /** |
| * A listener which can be registered to be informed of startup events |
| */ |
| @MakeNotStatic |
| private static volatile StartupStatusListener startupListener; |
| |
| private final DateFormat timeFormatter; |
| |
| protected LogWriterImpl() { |
| timeFormatter = DateFormatter.createDateFormat(); |
| } |
| |
| /** |
| * Gets the writer's level. |
| */ |
| @Override |
| public abstract int getLogWriterLevel(); |
| |
| @Override |
| public boolean isSecure() { |
| return false; |
| } |
| |
| public static String allowedLogLevels() { |
| StringBuilder sb = new StringBuilder(64); |
| for (int i = 0; i < levelNames.size(); i++) { |
| if (i != 0) { |
| sb.append('|'); |
| } |
| sb.append(levelNames.get(i)); |
| } |
| return sb.toString(); |
| } |
| |
| /** |
| * Gets the string representation for the given <code>level</code> int code. |
| */ |
| public static String levelToString(int level) { |
| switch (level) { |
| case ALL_LEVEL: |
| return "all"; |
| case FINEST_LEVEL: |
| return "finest"; |
| case FINER_LEVEL: |
| return "finer"; |
| case FINE_LEVEL: |
| return "fine"; |
| case CONFIG_LEVEL: |
| return "config"; |
| case INFO_LEVEL: |
| return "info"; |
| case WARNING_LEVEL: |
| return "warning"; |
| case ERROR_LEVEL: |
| return "error"; |
| case SEVERE_LEVEL: |
| return "severe"; |
| case NONE_LEVEL: |
| return "none"; |
| default: |
| return levelToStringSpecialCase(level); |
| } |
| } |
| |
| /** |
| * Handles the special cases for {@link #levelToString(int)} including such cases as the |
| * SECURITY_LOGGING_PREFIX and an invalid log level. |
| */ |
| private static String levelToStringSpecialCase(int levelWithFlags) { |
| if ((levelWithFlags & SECURITY_LOGGING_FLAG) != 0) { |
| // We know the flag is set so XOR will zero it out. |
| int level = levelWithFlags ^ SECURITY_LOGGING_FLAG; |
| return SecurityLogWriter.SECURITY_PREFIX + levelToString(level); |
| } else { |
| // Needed to prevent infinite recursion |
| // This signifies an unknown log level was used |
| return "level-" + levelWithFlags; |
| } |
| } |
| |
| protected static int getRealLogLevel(int levelWithFlags) { |
| if (levelWithFlags == NONE_LEVEL) { |
| return levelWithFlags; |
| } |
| return levelWithFlags & LOGGING_FLAGS_MASK; |
| } |
| |
| public static String join(Object[] array) { |
| return join(array, " "); |
| } |
| |
| public static String join(Object[] array, String joinString) { |
| return join(Arrays.asList(array), joinString); |
| } |
| |
| public static String join(List<?> list) { |
| return join(list, " "); |
| } |
| |
| public static String join(List<?> list, String joinString) { |
| StringBuilder result = new StringBuilder(80); |
| boolean firstTime = true; |
| for (Object object : list) { |
| if (firstTime) { |
| firstTime = false; |
| } else { |
| result.append(joinString); |
| } |
| result.append(object); |
| } |
| return result.toString(); |
| } |
| |
| /** |
| * Gets the level code for the given <code>levelName</code>. |
| * |
| * @throws IllegalArgumentException if an unknown level name is given. |
| */ |
| public static int levelNameToCode(String levelName) { |
| if ("all".equalsIgnoreCase(levelName)) { |
| return ALL_LEVEL; |
| } |
| if ("finest".equalsIgnoreCase(levelName) || "trace".equalsIgnoreCase(levelName)) { |
| return FINEST_LEVEL; |
| } |
| if ("finer".equalsIgnoreCase(levelName)) { |
| return FINER_LEVEL; |
| } |
| if ("fine".equalsIgnoreCase(levelName) || "debug".equalsIgnoreCase(levelName)) { |
| return FINE_LEVEL; |
| } |
| if ("config".equalsIgnoreCase(levelName)) { |
| return CONFIG_LEVEL; |
| } |
| if ("info".equalsIgnoreCase(levelName)) { |
| return INFO_LEVEL; |
| } |
| if ("warning".equalsIgnoreCase(levelName) || "warn".equalsIgnoreCase(levelName)) { |
| return WARNING_LEVEL; |
| } |
| if ("error".equalsIgnoreCase(levelName)) { |
| return ERROR_LEVEL; |
| } |
| if ("severe".equalsIgnoreCase(levelName) || "fatal".equalsIgnoreCase(levelName)) { |
| return SEVERE_LEVEL; |
| } |
| if ("none".equalsIgnoreCase(levelName)) { |
| return NONE_LEVEL; |
| } |
| try { |
| if (levelName.startsWith("level-")) { |
| String levelValue = levelName.substring("level-".length()); |
| return Integer.parseInt(levelValue); |
| } |
| } catch (NullPointerException | NumberFormatException ignore) { |
| // ignored |
| } |
| throw new IllegalArgumentException( |
| "Unknown log-level \"" + levelName + "\". Valid levels are: " + join(levelNames) + "."); |
| } |
| |
| /** |
| * Gets a String representation of the current time. |
| * |
| * @return a String representation of the current time. |
| */ |
| protected String getTimeStamp() { |
| return formatDate(new Date()); |
| } |
| |
| /** |
| * Convert a Date to a timestamp String. |
| * |
| * @param date a Date to format as a timestamp String. |
| * @return a String representation of the current time. |
| */ |
| protected String formatDate(Date date) { |
| try { |
| synchronized (timeFormatter) { |
| // Need sync: see bug 21858 |
| return timeFormatter.format(date); |
| } |
| } catch (Exception e1) { |
| // Fix bug 21857 |
| try { |
| return date.toString(); |
| } catch (Exception e2) { |
| try { |
| return Long.toString(date.getTime()); |
| } catch (Exception e3) { |
| return "timestampFormatFailed"; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns true if "severe" log messages are enabled. Returns false if "severe" log messages are |
| * disabled. |
| */ |
| @Override |
| public boolean severeEnabled() { |
| return getLogWriterLevel() <= SEVERE_LEVEL; |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "severe". |
| */ |
| @Override |
| public void severe(String message, Throwable throwable) { |
| if (severeEnabled()) { |
| put(SEVERE_LEVEL, message, throwable); |
| } |
| } |
| |
| /** |
| * Writes a message to this writer. The message level is "severe". |
| */ |
| @Override |
| public void severe(String message) { |
| severe(message, null); |
| } |
| |
| /** |
| * Writes an exception to this writer. The exception level is "severe". |
| */ |
| @Override |
| public void severe(Throwable throwable) { |
| severe("", throwable); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "severe". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void severe(StringId messageId, Object[] parameters, Throwable throwable) { |
| if (severeEnabled()) { |
| put(SEVERE_LEVEL, messageId, parameters, throwable); |
| } |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "severe". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void severe(StringId messageId, Object parameter, Throwable throwable) { |
| if (severeEnabled()) { |
| put(SEVERE_LEVEL, messageId, new Object[] {parameter}, throwable); |
| } |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "severe". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void severe(StringId messageId, Throwable throwable) { |
| severe(messageId, null, throwable); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "severe". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void severe(StringId messageId, Object[] parameters) { |
| severe(messageId, parameters, null); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "severe". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void severe(StringId messageId, Object parameter) { |
| severe(messageId, parameter, null); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "severe". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void severe(StringId messageId) { |
| severe(messageId, null, null); |
| } |
| |
| /** |
| * @return true if "error" log messages are enabled. |
| */ |
| @Override |
| public boolean errorEnabled() { |
| return getLogWriterLevel() <= ERROR_LEVEL; |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "error". |
| */ |
| @Override |
| public void error(String message, Throwable throwable) { |
| if (errorEnabled()) { |
| put(ERROR_LEVEL, message, throwable); |
| } |
| } |
| |
| /** |
| * Writes a message to this writer. The message level is "error". |
| */ |
| @Override |
| public void error(String message) { |
| error(message, null); |
| } |
| |
| /** |
| * Writes an exception to this writer. The exception level is "error". |
| */ |
| @Override |
| public void error(Throwable throwable) { |
| error("", throwable); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "error". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void error(StringId messageId, Object[] parameters, Throwable throwable) { |
| if (errorEnabled()) { |
| put(ERROR_LEVEL, messageId, parameters, throwable); |
| } |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "error". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void error(StringId messageId, Object parameter, Throwable throwable) { |
| if (errorEnabled()) { |
| put(ERROR_LEVEL, messageId, new Object[] {parameter}, throwable); |
| } |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "error". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void error(StringId messageId, Throwable throwable) { |
| error(messageId, null, throwable); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "error". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void error(StringId messageId, Object[] parameters) { |
| error(messageId, parameters, null); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "error". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void error(StringId messageId, Object parameter) { |
| error(messageId, parameter, null); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "error". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void error(StringId messageId) { |
| error(messageId, null, null); |
| } |
| |
| /** |
| * @return true if "warning" log messages are enabled. |
| */ |
| @Override |
| public boolean warningEnabled() { |
| return getLogWriterLevel() <= WARNING_LEVEL; |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "warning". |
| */ |
| @Override |
| public void warning(String message, Throwable throwable) { |
| if (warningEnabled()) { |
| put(WARNING_LEVEL, message, throwable); |
| } |
| } |
| |
| /** |
| * Writes a message to this writer. The message level is "warning". |
| */ |
| @Override |
| public void warning(String message) { |
| warning(message, null); |
| } |
| |
| /** |
| * Writes an exception to this writer. The exception level is "warning". |
| */ |
| @Override |
| public void warning(Throwable throwable) { |
| warning("", throwable); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "warning". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void warning(StringId messageId, Object[] parameters, Throwable throwable) { |
| if (warningEnabled()) { |
| put(WARNING_LEVEL, messageId, parameters, throwable); |
| } |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "warning". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void warning(StringId messageId, Object parameter, Throwable throwable) { |
| if (warningEnabled()) { |
| put(WARNING_LEVEL, messageId, new Object[] {parameter}, throwable); |
| } |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "warning". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void warning(StringId messageId, Throwable throwable) { |
| warning(messageId, null, throwable); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "warning". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void warning(StringId messageId, Object[] parameters) { |
| warning(messageId, parameters, null); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "warning". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void warning(StringId messageId, Object parameter) { |
| warning(messageId, parameter, null); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "warning". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void warning(StringId messageId) { |
| warning(messageId, null, null); |
| } |
| |
| /** |
| * @return true if "info" log messages are enabled. |
| */ |
| @Override |
| public boolean infoEnabled() { |
| return getLogWriterLevel() <= INFO_LEVEL; |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "information". |
| */ |
| @Override |
| public void info(String message, Throwable throwable) { |
| if (infoEnabled()) { |
| put(INFO_LEVEL, message, throwable); |
| } |
| } |
| |
| /** |
| * Writes a message to this writer. The message level is "information". |
| */ |
| @Override |
| public void info(String message) { |
| info(message, null); |
| } |
| |
| /** |
| * Writes an exception to this writer. The exception level is "information". |
| */ |
| @Override |
| public void info(Throwable throwable) { |
| info("", throwable); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "info". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void info(StringId messageId, Object[] parameters, Throwable throwable) { |
| if (infoEnabled()) { |
| put(INFO_LEVEL, messageId, parameters, throwable); |
| } |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "info". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void info(StringId messageId, Object parameter, Throwable throwable) { |
| if (infoEnabled()) { |
| put(INFO_LEVEL, messageId, new Object[] {parameter}, throwable); |
| } |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "info". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void info(StringId messageId, Throwable throwable) { |
| info(messageId, null, throwable); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "info". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void info(StringId messageId, Object[] parameters) { |
| info(messageId, parameters, null); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "info". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void info(StringId messageId, Object parameter) { |
| info(messageId, parameter, null); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "info". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void info(StringId messageId) { |
| info(messageId, null, null); |
| } |
| |
| /** |
| * @return true if "config" log messages are enabled. |
| */ |
| @Override |
| public boolean configEnabled() { |
| return getLogWriterLevel() <= CONFIG_LEVEL; |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "config". |
| */ |
| @Override |
| public void config(String message, Throwable throwable) { |
| if (configEnabled()) { |
| put(CONFIG_LEVEL, message, throwable); |
| } |
| } |
| |
| /** |
| * Writes a message to this writer. The message level is "config". |
| */ |
| @Override |
| public void config(String message) { |
| config(message, null); |
| } |
| |
| /** |
| * Writes an exception to this writer. The exception level is "config". |
| */ |
| @Override |
| public void config(Throwable throwable) { |
| config("", throwable); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "config". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void config(StringId messageId, Object[] parameters, Throwable throwable) { |
| if (configEnabled()) { |
| put(CONFIG_LEVEL, messageId, parameters, throwable); |
| } |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "config". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void config(StringId messageId, Object parameter, Throwable throwable) { |
| if (configEnabled()) { |
| put(CONFIG_LEVEL, messageId, new Object[] {parameter}, throwable); |
| } |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "config". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void config(StringId messageId, Throwable throwable) { |
| config(messageId, null, throwable); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "config". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void config(StringId messageId, Object[] parameters) { |
| config(messageId, parameters, null); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "config". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void config(StringId messageId, Object parameter) { |
| config(messageId, parameter, null); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "config". |
| * |
| * @since GemFire 6.0 |
| */ |
| @Override |
| public void config(StringId messageId) { |
| config(messageId, null, null); |
| } |
| |
| /** |
| * @return true if "fine" log messages are enabled. |
| */ |
| @Override |
| public boolean fineEnabled() { |
| return getLogWriterLevel() <= FINE_LEVEL; |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "fine". |
| */ |
| @Override |
| public void fine(String message, Throwable throwable) { |
| if (fineEnabled()) { |
| put(FINE_LEVEL, message, throwable); |
| } |
| } |
| |
| /** |
| * Writes a message to this writer. The message level is "fine". |
| */ |
| @Override |
| public void fine(String message) { |
| fine(message, null); |
| } |
| |
| /** |
| * Writes an exception to this writer. The exception level is "fine". |
| */ |
| @Override |
| public void fine(Throwable throwable) { |
| fine(null, throwable); |
| } |
| |
| /** |
| * Returns true if "finer" log messages are enabled. Returns false if "finer" log messages are |
| * disabled. |
| */ |
| @Override |
| public boolean finerEnabled() { |
| return getLogWriterLevel() <= FINER_LEVEL; |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "finer". |
| */ |
| @Override |
| public void finer(String message, Throwable throwable) { |
| if (finerEnabled()) { |
| put(FINER_LEVEL, message, throwable); |
| } |
| } |
| |
| /** |
| * Writes a message to this writer. The message level is "finer". |
| */ |
| @Override |
| public void finer(String message) { |
| finer(message, null); |
| } |
| |
| /** |
| * Writes an exception to this writer. The exception level is "finer". |
| */ |
| @Override |
| public void finer(Throwable throwable) { |
| finer(null, throwable); |
| } |
| |
| /** |
| * Log a method entry. |
| * <p> |
| * The logging is done using the <code>finer</code> level. The string message will start with |
| * <code>"ENTRY"</code> and include the class and method names. |
| * |
| * @param sourceClass Name of class that issued the logging request. |
| * @param sourceMethod Name of the method that issued the logging request. |
| */ |
| @Override |
| public void entering(String sourceClass, String sourceMethod) { |
| if (finerEnabled()) { |
| finer("ENTRY " + sourceClass + ":" + sourceMethod); |
| } |
| } |
| |
| /** |
| * Log a method return. |
| * <p> |
| * The logging is done using the <code>finer</code> level. The string message will start with |
| * <code>"RETURN"</code> and include the class and method names. |
| * |
| * @param sourceClass Name of class that issued the logging request. |
| * @param sourceMethod Name of the method that issued the logging request. |
| */ |
| @Override |
| public void exiting(String sourceClass, String sourceMethod) { |
| if (finerEnabled()) { |
| finer("RETURN " + sourceClass + ":" + sourceMethod); |
| } |
| } |
| |
| /** |
| * Log throwing an exception. |
| * <p> |
| * Use to log that a method is terminating by throwing an exception. The logging is done using the |
| * <code>finer</code> level. |
| * <p> |
| * This is a convenience method that could be done instead by calling |
| * {@link #finer(String, Throwable)}. The string message will start with <code>"THROW"</code> and |
| * include the class and method names. |
| * |
| * @param sourceClass Name of class that issued the logging request. |
| * @param sourceMethod Name of the method that issued the logging request. |
| * @param thrown The Throwable that is being thrown. |
| */ |
| @Override |
| public void throwing(String sourceClass, String sourceMethod, Throwable thrown) { |
| if (finerEnabled()) { |
| finer("THROW " + sourceClass + ":" + sourceMethod, thrown); |
| } |
| } |
| |
| /** |
| * Returns true if "finest" log messages are enabled. Returns false if "finest" log messages are |
| * disabled. |
| */ |
| @Override |
| public boolean finestEnabled() { |
| return getLogWriterLevel() <= FINEST_LEVEL; |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. The message level is "finest". |
| */ |
| @Override |
| public void finest(String message, Throwable throwable) { |
| if (finestEnabled()) { |
| put(FINEST_LEVEL, message, throwable); |
| } |
| } |
| |
| /** |
| * Writes a message to this writer. The message level is "finest". |
| */ |
| @Override |
| public void finest(String message) { |
| finest(message, null); |
| } |
| |
| /** |
| * Writes an exception to this writer. The exception level is "finest". |
| */ |
| @Override |
| public void finest(Throwable throwable) { |
| finest(null, throwable); |
| } |
| |
| /** |
| * Writes both a message and exception to this writer. If a startup listener is registered, the |
| * message will be written to the listener as well to be reported to a user. |
| * |
| * @since GemFire 7.0 |
| */ |
| public void startup(StringId msgID, Object[] params) { |
| String message = msgID.toLocalizedString(params); |
| |
| StartupStatusListener listener = startupListener; |
| if (listener != null) { |
| listener.setStatus(message); |
| } |
| |
| if (infoEnabled()) { |
| put(INFO_LEVEL, message, null); |
| } |
| } |
| |
| /** |
| * Logs a message and an exception of the given level. |
| * |
| * @param messageLevel the level code for the message to log |
| * @param message the actual message to log |
| * @param throwable the actual Exception to log |
| */ |
| @Override |
| public abstract void put(int messageLevel, String message, Throwable throwable); |
| |
| /** |
| * Logs a message and an exception of the given level. |
| * |
| * @param messageLevel the level code for the message to log |
| * @param messageId A locale agnostic form of the message |
| * @param parameters the Object arguments to plug into the message |
| * @param throwable the actual Exception to log |
| */ |
| @Override |
| public abstract void put(int messageLevel, StringId messageId, Object[] parameters, |
| Throwable throwable); |
| |
| /** |
| * formatText manipulates \n and \r chars but supports Windows and Linux/Unix/Mac |
| */ |
| static void formatText(PrintWriter writer, String target, int initialLength) { |
| BreakIterator boundary = BreakIterator.getLineInstance(); |
| boundary.setText(target); |
| int start = boundary.first(); |
| int end = boundary.next(); |
| int lineLength = initialLength; |
| |
| while (end != BreakIterator.DONE) { |
| // Look at the end and only accept whitespace breaks |
| char endChar = target.charAt(end - 1); |
| while (!Character.isWhitespace(endChar)) { |
| int lastEnd = end; |
| end = boundary.next(); |
| if (end == BreakIterator.DONE) { |
| // give up. We are at the end of the string |
| end = lastEnd; |
| break; |
| } |
| endChar = target.charAt(end - 1); |
| } |
| int wordEnd = end; |
| if (endChar == '\n') { |
| // trim off the \n since println will do it for us |
| wordEnd--; |
| if (wordEnd > 0 && target.charAt(wordEnd - 1) == '\r') { |
| wordEnd--; |
| } |
| } else if (endChar == '\t') { |
| // figure tabs use 8 characters |
| lineLength += 7; |
| } |
| String word = target.substring(start, wordEnd); |
| lineLength += word.length(); |
| writer.print(word); |
| if (endChar == '\n' || endChar == '\r') { |
| // force end of line |
| writer.println(); |
| writer.print(" "); |
| lineLength = 2; |
| } |
| start = end; |
| end = boundary.next(); |
| } |
| if (lineLength != 0) { |
| writer.println(); |
| } |
| } |
| |
| /** |
| * Check if a message of the given level would actually be logged by this logger. This check is |
| * based on the Logger effective level. |
| * |
| * @param level a message logging level |
| * @return true if the given message level is currently being logged. |
| */ |
| private boolean isLoggable(int level) { |
| return getLogWriterLevel() <= level; |
| } |
| |
| /** |
| * Log a message, with associated Throwable information. If the logger is currently enabled for |
| * the given message level then the given message is logged. |
| * |
| * @param level One of the message level identifiers, e.g. SEVERE |
| * @param message The string message |
| * @param thrown - Throwable associated with log message. |
| */ |
| public void log(int level, String message, Throwable thrown) { |
| if (isLoggable(level)) { |
| put(level, message, thrown); |
| } |
| } |
| |
| /** |
| * Log a message. If the logger is currently enabled for the given message level then the given |
| * message is logged. |
| * |
| * @param level One of the message level identifiers, e.g. SEVERE |
| * @param message The string message |
| */ |
| public void log(int level, String message) { |
| if (isLoggable(level)) { |
| put(level, message, null); |
| } |
| } |
| |
| @Override |
| public Handler getHandler() { |
| return new GemFireHandler(this); |
| } |
| |
| /** Utility to get a stack trace as a string from a Throwable */ |
| public static String getStackTrace(Throwable throwable) { |
| StringWriter sw = new StringWriter(); |
| throwable.printStackTrace(new PrintWriter(sw, true)); |
| return sw.toString(); |
| } |
| |
| /** |
| * Utility to periodically log a stack trace for a thread. The thread should be alive when this |
| * method is invoked. |
| * |
| * @param toStdout whether to log to stdout or to this log writer |
| * @param targetThread the thread to snapshot |
| * @param interval millis to wait betweeen snaps |
| * @param done when to stop snapshotting (also ceases if targetThread dies) |
| */ |
| public void logTraces(final boolean toStdout, final Thread targetThread, final int interval, |
| final AtomicBoolean done) { |
| if (targetThread == null) { |
| return; |
| } |
| Thread watcherThread = |
| new LoggingThread("Stack Tracer for '" + targetThread.getName() + "'", false, () -> { |
| while (!done.get()) { |
| try { |
| Thread.sleep(500); |
| } catch (InterruptedException e) { |
| return; |
| } |
| if (!done.get() && targetThread.isAlive()) { |
| StringBuilder sb = new StringBuilder(500); |
| if (toStdout) { |
| sb.append("[trace ").append(getTimeStamp()).append("] "); |
| } |
| StackTraceElement[] els = targetThread.getStackTrace(); |
| sb.append("Stack trace for '").append(targetThread).append("'") |
| .append(lineSeparator()); |
| if (els.length > 0) { |
| for (int i = 0; i < els.length; i++) { |
| sb.append("\tat ").append(els[i]).append(lineSeparator()); |
| } |
| } else { |
| sb.append(" no stack").append(lineSeparator()); |
| } |
| if (toStdout) { |
| System.out.println(sb); |
| } else { |
| info(sb.toString()); |
| } |
| } |
| } |
| }); |
| watcherThread.start(); |
| } |
| |
| /** Utility to get a stack trace for a thread */ |
| public static StringBuilder getStackTrace(Thread targetThread) { |
| StringBuilder sb = new StringBuilder(500); |
| StackTraceElement[] els = targetThread.getStackTrace(); |
| sb.append("Stack trace for '").append(targetThread).append("'").append(lineSeparator()); |
| if (els.length > 0) { |
| for (int i = 0; i < els.length; i++) { |
| sb.append("\tat ").append(els[i]).append(lineSeparator()); |
| } |
| } else { |
| sb.append(" no stack").append(lineSeparator()); |
| } |
| return sb; |
| } |
| |
| @Override |
| public LogWriter convertToLogWriter() { |
| return this; |
| } |
| |
| @Override |
| public LogWriterI18n convertToLogWriterI18n() { |
| return this; |
| } |
| |
| public static void setStartupListener(StartupStatusListener mainListener) { |
| startupListener = mainListener; |
| } |
| |
| public static StartupStatusListener getStartupListener() { |
| return startupListener; |
| } |
| } |