| /* |
| * 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.logging.log4j.core; |
| |
| import java.io.ObjectStreamException; |
| import java.io.Serializable; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.logging.log4j.Level; |
| import org.apache.logging.log4j.Marker; |
| import org.apache.logging.log4j.core.config.Configuration; |
| import org.apache.logging.log4j.core.config.LoggerConfig; |
| import org.apache.logging.log4j.core.config.ReliabilityStrategy; |
| import org.apache.logging.log4j.core.filter.CompositeFilter; |
| import org.apache.logging.log4j.message.Message; |
| import org.apache.logging.log4j.message.MessageFactory; |
| import org.apache.logging.log4j.message.SimpleMessage; |
| import org.apache.logging.log4j.spi.AbstractLogger; |
| import org.apache.logging.log4j.util.Strings; |
| import org.apache.logging.log4j.util.Supplier; |
| |
| /** |
| * The core implementation of the {@link org.apache.logging.log4j.Logger} interface. Besides providing an implementation |
| * of all the Logger methods, this class also provides some convenience methods for Log4j 1.x compatibility as well as |
| * access to the {@link org.apache.logging.log4j.core.Filter Filters} and {@link org.apache.logging.log4j.core.Appender |
| * Appenders} associated with this Logger. Note that access to these underlying objects is provided primarily for use in |
| * unit tests or bridging legacy Log4j 1.x code. Future versions of this class may or may not include the various |
| * methods that are noted as not being part of the public API. |
| * |
| * TODO All the isEnabled methods could be pushed into a filter interface. Not sure of the utility of having isEnabled |
| * be able to examine the message pattern and parameters. (RG) Moving the isEnabled methods out of Logger noticeably |
| * impacts performance. The message pattern and parameters are required so that they can be used in global filters. |
| */ |
| public class Logger extends AbstractLogger implements Supplier<LoggerConfig> { |
| |
| private static final long serialVersionUID = 1L; |
| |
| /** |
| * Config should be consistent across threads. |
| */ |
| protected volatile PrivateConfig privateConfig; |
| |
| // FIXME: ditto to the above |
| private final LoggerContext context; |
| |
| /** |
| * The constructor. |
| * |
| * @param context The LoggerContext this Logger is associated with. |
| * @param messageFactory The message factory. |
| * @param name The name of the Logger. |
| */ |
| protected Logger(final LoggerContext context, final String name, final MessageFactory messageFactory) { |
| super(name, messageFactory); |
| this.context = context; |
| privateConfig = new PrivateConfig(context.getConfiguration(), this); |
| } |
| |
| protected Object writeReplace() throws ObjectStreamException { |
| return new LoggerProxy(getName(), getMessageFactory()); |
| } |
| |
| /** |
| * This method is only used for 1.x compatibility. Returns the parent of this Logger. If it doesn't already exist |
| * return a temporary Logger. |
| * |
| * @return The parent Logger. |
| */ |
| public Logger getParent() { |
| final LoggerConfig lc = privateConfig.loggerConfig.getName().equals(getName()) ? privateConfig.loggerConfig |
| .getParent() : privateConfig.loggerConfig; |
| if (lc == null) { |
| return null; |
| } |
| final String lcName = lc.getName(); |
| final MessageFactory messageFactory = getMessageFactory(); |
| if (context.hasLogger(lcName, messageFactory)) { |
| return context.getLogger(lcName, messageFactory); |
| } |
| return new Logger(context, lcName, messageFactory); |
| } |
| |
| /** |
| * Returns the LoggerContext this Logger is associated with. |
| * |
| * @return the LoggerContext. |
| */ |
| public LoggerContext getContext() { |
| return context; |
| } |
| |
| /** |
| * This method is not exposed through the public API and is provided primarily for unit testing. |
| * <p> |
| * If the new level is null, this logger inherits the level from its parent. |
| * </p> |
| * |
| * @param level The Level to use on this Logger, may be null. |
| */ |
| public synchronized void setLevel(final Level level) { |
| if (level == getLevel()) { |
| return; |
| } |
| Level actualLevel; |
| if (level != null) { |
| actualLevel = level; |
| } else { |
| final Logger parent = getParent(); |
| actualLevel = parent != null ? parent.getLevel() : privateConfig.loggerConfigLevel; |
| } |
| privateConfig = new PrivateConfig(privateConfig, actualLevel); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.logging.log4j.util.Supplier#get() |
| */ |
| @Override |
| public LoggerConfig get() { |
| return privateConfig.loggerConfig; |
| } |
| |
| @Override |
| public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message, |
| final Throwable t) { |
| final Message msg = message == null ? new SimpleMessage(Strings.EMPTY) : message; |
| final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy(); |
| strategy.log(this, getName(), fqcn, marker, level, msg, t); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Throwable t) { |
| return privateConfig.filter(level, marker, message, t); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message) { |
| return privateConfig.filter(level, marker, message); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Object... params) { |
| return privateConfig.filter(level, marker, message, params); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0) { |
| return privateConfig.filter(level, marker, message, p0); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, |
| final Object p1) { |
| return privateConfig.filter(level, marker, message, p0, p1); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, |
| final Object p1, final Object p2) { |
| return privateConfig.filter(level, marker, message, p0, p1, p2); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, |
| final Object p1, final Object p2, final Object p3) { |
| return privateConfig.filter(level, marker, message, p0, p1, p2, p3); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4) { |
| return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4, final Object p5) { |
| return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4, p5); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4, final Object p5, final Object p6) { |
| return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4, p5, p6); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4, final Object p5, final Object p6, |
| final Object p7) { |
| return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4, p5, p6, p7); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4, final Object p5, final Object p6, |
| final Object p7, final Object p8) { |
| return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4, p5, p6, p7, p8); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final String message, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4, final Object p5, final Object p6, |
| final Object p7, final Object p8, final Object p9) { |
| return privateConfig.filter(level, marker, message, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final CharSequence message, final Throwable t) { |
| return privateConfig.filter(level, marker, message, t); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final Object message, final Throwable t) { |
| return privateConfig.filter(level, marker, message, t); |
| } |
| |
| @Override |
| public boolean isEnabled(final Level level, final Marker marker, final Message message, final Throwable t) { |
| return privateConfig.filter(level, marker, message, t); |
| } |
| |
| /** |
| * This method is not exposed through the public API and is used primarily for unit testing. |
| * |
| * @param appender The Appender to add to the Logger. |
| */ |
| public void addAppender(final Appender appender) { |
| privateConfig.config.addLoggerAppender(this, appender); |
| } |
| |
| /** |
| * This method is not exposed through the public API and is used primarily for unit testing. |
| * |
| * @param appender The Appender to remove from the Logger. |
| */ |
| public void removeAppender(final Appender appender) { |
| privateConfig.loggerConfig.removeAppender(appender.getName()); |
| } |
| |
| /** |
| * This method is not exposed through the public API and is used primarily for unit testing. |
| * |
| * @return A Map containing the Appender's name as the key and the Appender as the value. |
| */ |
| public Map<String, Appender> getAppenders() { |
| return privateConfig.loggerConfig.getAppenders(); |
| } |
| |
| /** |
| * This method is not exposed through the public API and is used primarily for unit testing. |
| * |
| * @return An Iterator over all the Filters associated with the Logger. |
| */ |
| // FIXME: this really ought to be an Iterable instead of an Iterator |
| public Iterator<Filter> getFilters() { |
| final Filter filter = privateConfig.loggerConfig.getFilter(); |
| if (filter == null) { |
| return new ArrayList<Filter>().iterator(); |
| } else if (filter instanceof CompositeFilter) { |
| return ((CompositeFilter) filter).iterator(); |
| } else { |
| final List<Filter> filters = new ArrayList<>(); |
| filters.add(filter); |
| return filters.iterator(); |
| } |
| } |
| |
| /** |
| * Gets the Level associated with the Logger. |
| * |
| * @return the Level associate with the Logger. |
| */ |
| @Override |
| public Level getLevel() { |
| return privateConfig.loggerConfigLevel; |
| } |
| |
| /** |
| * This method is not exposed through the public API and is used primarily for unit testing. |
| * |
| * @return The number of Filters associated with the Logger. |
| */ |
| public int filterCount() { |
| final Filter filter = privateConfig.loggerConfig.getFilter(); |
| if (filter == null) { |
| return 0; |
| } else if (filter instanceof CompositeFilter) { |
| return ((CompositeFilter) filter).size(); |
| } |
| return 1; |
| } |
| |
| /** |
| * This method is not exposed through the public API and is used primarily for unit testing. |
| * |
| * @param filter The Filter to add. |
| */ |
| public void addFilter(final Filter filter) { |
| privateConfig.config.addLoggerFilter(this, filter); |
| } |
| |
| /** |
| * This method is not exposed through the public API and is present only to support the Log4j 1.2 compatibility |
| * bridge. |
| * |
| * @return true if the associated LoggerConfig is additive, false otherwise. |
| */ |
| public boolean isAdditive() { |
| return privateConfig.loggerConfig.isAdditive(); |
| } |
| |
| /** |
| * This method is not exposed through the public API and is present only to support the Log4j 1.2 compatibility |
| * bridge. |
| * |
| * @param additive Boolean value to indicate whether the Logger is additive or not. |
| */ |
| public void setAdditive(final boolean additive) { |
| privateConfig.config.setLoggerAdditive(this, additive); |
| } |
| |
| /** |
| * Associates this Logger with a new Configuration. This method is not |
| * exposed through the public API. |
| * <p> |
| * There are two ways this could be used to guarantee all threads are aware |
| * of changes to config. |
| * <ol> |
| * <li>Synchronize this method. Accessors don't need to be synchronized as |
| * Java will treat all variables within a synchronized block as volatile. |
| * </li> |
| * <li>Declare the variable volatile. Option 2 is used here as the |
| * performance cost is very low and it does a better job at documenting how |
| * it is used.</li> |
| * |
| * @param newConfig |
| * The new Configuration. |
| */ |
| protected void updateConfiguration(final Configuration newConfig) { |
| this.privateConfig = new PrivateConfig(newConfig, this); |
| } |
| |
| /** |
| * The binding between a Logger and its configuration. |
| */ |
| protected class PrivateConfig { |
| // config fields are public to make them visible to Logger subclasses |
| /** LoggerConfig to delegate the actual logging to. */ |
| public final LoggerConfig loggerConfig; // SUPPRESS CHECKSTYLE |
| /** The current Configuration associated with the LoggerConfig. */ |
| public final Configuration config; // SUPPRESS CHECKSTYLE |
| private final Level loggerConfigLevel; |
| private final int intLevel; |
| private final Logger logger; |
| |
| public PrivateConfig(final Configuration config, final Logger logger) { |
| this.config = config; |
| this.loggerConfig = config.getLoggerConfig(getName()); |
| this.loggerConfigLevel = this.loggerConfig.getLevel(); |
| this.intLevel = this.loggerConfigLevel.intLevel(); |
| this.logger = logger; |
| } |
| |
| public PrivateConfig(final PrivateConfig pc, final Level level) { |
| this.config = pc.config; |
| this.loggerConfig = pc.loggerConfig; |
| this.loggerConfigLevel = level; |
| this.intLevel = this.loggerConfigLevel.intLevel(); |
| this.logger = pc.logger; |
| } |
| |
| public PrivateConfig(final PrivateConfig pc, final LoggerConfig lc) { |
| this.config = pc.config; |
| this.loggerConfig = lc; |
| this.loggerConfigLevel = lc.getLevel(); |
| this.intLevel = this.loggerConfigLevel.intLevel(); |
| this.logger = pc.logger; |
| } |
| |
| // LOG4J2-151: changed visibility to public |
| public void logEvent(final LogEvent event) { |
| loggerConfig.log(event); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Throwable t) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, (Object) msg, t); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Object... p1) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, p1); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Object p0) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, p0); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Object p0, |
| final Object p1) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Object p0, |
| final Object p1, final Object p2) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Object p0, |
| final Object p1, final Object p2, final Object p3) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4, final Object p5) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4, final Object p5, final Object p6) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4, final Object p5, final Object p6, |
| final Object p7) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6, p7); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4, final Object p5, final Object p6, |
| final Object p7, final Object p8) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6, p7, p8); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final String msg, final Object p0, |
| final Object p1, final Object p2, final Object p3, |
| final Object p4, final Object p5, final Object p6, |
| final Object p7, final Object p8, final Object p9) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6, p7, p8, |
| p9); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final CharSequence msg, final Throwable t) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, t); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final Object msg, final Throwable t) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, t); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| boolean filter(final Level level, final Marker marker, final Message msg, final Throwable t) { |
| final Filter filter = config.getFilter(); |
| if (filter != null) { |
| final Filter.Result r = filter.filter(logger, level, marker, msg, t); |
| if (r != Filter.Result.NEUTRAL) { |
| return r == Filter.Result.ACCEPT; |
| } |
| } |
| return level != null && intLevel >= level.intLevel(); |
| } |
| |
| @Override |
| public String toString() { |
| final StringBuilder builder = new StringBuilder(); |
| builder.append("PrivateConfig [loggerConfig="); |
| builder.append(loggerConfig); |
| builder.append(", config="); |
| builder.append(config); |
| builder.append(", loggerConfigLevel="); |
| builder.append(loggerConfigLevel); |
| builder.append(", intLevel="); |
| builder.append(intLevel); |
| builder.append(", logger="); |
| builder.append(logger); |
| builder.append("]"); |
| return builder.toString(); |
| } |
| } |
| |
| /** |
| * Serialization proxy class for Logger. Since the LoggerContext and config information can be reconstructed on the |
| * fly, the only information needed for a Logger are what's available in AbstractLogger. |
| * |
| * @since 2.5 |
| */ |
| protected static class LoggerProxy implements Serializable { |
| private static final long serialVersionUID = 1L; |
| |
| private final String name; |
| private final MessageFactory messageFactory; |
| |
| public LoggerProxy(final String name, final MessageFactory messageFactory) { |
| this.name = name; |
| this.messageFactory = messageFactory; |
| } |
| |
| protected Object readResolve() throws ObjectStreamException { |
| return new Logger(LoggerContext.getContext(), name, messageFactory); |
| } |
| } |
| |
| /** |
| * Returns a String representation of this instance in the form {@code "name:level[ in context_name]"}. |
| * |
| * @return A String describing this Logger instance. |
| */ |
| @Override |
| public String toString() { |
| final String nameLevel = Strings.EMPTY + getName() + ':' + getLevel(); |
| if (context == null) { |
| return nameLevel; |
| } |
| final String contextName = context.getName(); |
| return contextName == null ? nameLevel : nameLevel + " in " + contextName; |
| } |
| |
| @Override |
| public boolean equals(final Object o) { |
| if (this == o) { |
| return true; |
| } |
| if (o == null || getClass() != o.getClass()) { |
| return false; |
| } |
| final Logger that = (Logger) o; |
| return getName().equals(that.getName()); |
| } |
| |
| @Override |
| public int hashCode() { |
| return getName().hashCode(); |
| } |
| } |