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

org.jboss.logmanager.ExtHandler Maven / Gradle / Ivy

/*
 * Copyright 2018 Red Hat, Inc.
 *
 * 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 org.jboss.logmanager;

import java.io.UnsupportedEncodingException;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.logging.ErrorManager;
import java.util.logging.Filter;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;

import org.jboss.logmanager.errormanager.OnlyOnceErrorManager;
import org.jboss.logmanager.handlers.FlushableCloseable;

/**
 * An extended logger handler.  Use this class as a base class for log handlers which require {@code ExtLogRecord}
 * instances.
 */
public abstract class ExtHandler extends Handler implements FlushableCloseable {

    private volatile boolean autoFlush = true;
    private volatile boolean enabled = true;
    private volatile boolean closeChildren;
    private static final ErrorManager DEFAULT_ERROR_MANAGER = new OnlyOnceErrorManager();

    /**
     * The sub-handlers for this handler.  May only be updated using the {@link #handlersUpdater} atomic updater.  The array
     * instance should not be modified (treat as immutable).
     */
    @SuppressWarnings("unused")
    protected volatile Handler[] handlers;

    /**
     * The atomic updater for the {@link #handlers} field.
     */
    protected static final AtomicArray handlersUpdater = AtomicArray.create(AtomicReferenceFieldUpdater.newUpdater(ExtHandler.class, Handler[].class, "handlers"), Handler.class);

    /**
     * Construct a new instance.
     */
    protected ExtHandler() {
        handlersUpdater.clear(this);
        closeChildren = true;
        super.setErrorManager(DEFAULT_ERROR_MANAGER);
    }

    /** {@inheritDoc} */
    public void publish(final LogRecord record) {
        if (enabled && record != null && isLoggable(record)) {
            doPublish(ExtLogRecord.wrap(record));
        }
    }

    /**
     * Publish an {@code ExtLogRecord}.
     * 

* The logging request was made initially to a Logger object, which initialized the LogRecord and forwarded it here. *

* The {@code ExtHandler} is responsible for formatting the message, when and if necessary. The formatting should * include localization. * * @param record the log record to publish */ public void publish(final ExtLogRecord record) { if (enabled && record != null && isLoggable(record)) try { doPublish(record); } catch (Exception e) { reportError("Handler publication threw an exception", e, ErrorManager.WRITE_FAILURE); } catch (Throwable ignored) { } } /** * Publish a log record to each nested handler. * * @param record the log record to publish */ protected void publishToNestedHandlers(final ExtLogRecord record) { if (record != null) { for (Handler handler : getHandlers()) try { handler.publish(record); } catch (Exception e) { reportError(handler, "Nested handler publication threw an exception", e, ErrorManager.WRITE_FAILURE); } catch (Throwable ignored) { } } } /** * Do the actual work of publication; the record will have been filtered already. The default implementation * does nothing except to flush if the {@code autoFlush} property is set to {@code true}; if this behavior is to be * preserved in a subclass then this method should be called after the record is physically written. * * @param record the log record to publish */ protected void doPublish(final ExtLogRecord record) { if (autoFlush) flush(); } /** * Add a sub-handler to this handler. Some handler types do not utilize sub-handlers. * * @param handler the handler to add */ public void addHandler(Handler handler) { if (handler == null) { throw new NullPointerException("handler is null"); } handlersUpdater.add(this, handler); } /** * Remove a sub-handler from this handler. Some handler types do not utilize sub-handlers. * * @param handler the handler to remove */ public void removeHandler(Handler handler) throws SecurityException { if (handler == null) { return; } handlersUpdater.remove(this, handler, true); } /** * Get a copy of the sub-handlers array. Since the returned value is a copy, it may be freely modified. * * @return a copy of the sub-handlers array */ public Handler[] getHandlers() { final Handler[] handlers = this.handlers; return handlers.length > 0 ? handlers.clone() : handlers; } /** * A convenience method to atomically get and clear all sub-handlers. * * @return the old sub-handler array */ public Handler[] clearHandlers() throws SecurityException { final Handler[] handlers = this.handlers; handlersUpdater.clear(this); return handlers.length > 0 ? handlers.clone() : handlers; } /** * A convenience method to atomically get and replace the sub-handler array. * * @param newHandlers the new sub-handlers * @return the old sub-handler array */ public Handler[] setHandlers(final Handler[] newHandlers) throws SecurityException { if (newHandlers == null) { throw new IllegalArgumentException("newHandlers is null"); } if (newHandlers.length == 0) { return clearHandlers(); } else { final Handler[] handlers = handlersUpdater.getAndSet(this, newHandlers); return handlers.length > 0 ? handlers.clone() : handlers; } } /** * Determine if this handler will auto-flush. * * @return {@code true} if auto-flush is enabled */ public boolean isAutoFlush() { return autoFlush; } /** * Change the autoflush setting for this handler. * * @param autoFlush {@code true} to automatically flush after each write; false otherwise */ public void setAutoFlush(final boolean autoFlush) throws SecurityException { this.autoFlush = autoFlush; if (autoFlush) { flush(); } } /** * Enables or disables the handler based on the value passed in. * * @param enabled {@code true} to enable the handler or {@code false} to disable the handler. */ public final void setEnabled(final boolean enabled) throws SecurityException { this.enabled = enabled; } /** * Determine if the handler is enabled. * * @return {@code true} if the handler is enabled, otherwise {@code false}. */ public final boolean isEnabled() { return enabled; } /** * Indicates whether or not children handlers should be closed when this handler is {@linkplain #close() closed}. * * @return {@code true} if the children handlers should be closed when this handler is closed, {@code false} if * children handlers should not be closed when this handler is closed */ public boolean isCloseChildren() { return closeChildren; } /** * Sets whether or not children handlers should be closed when this handler is {@linkplain #close() closed}. * * @param closeChildren {@code true} if all children handlers should be closed when this handler is closed, * {@code false} if children handlers will not be closed when this handler * is closed */ public void setCloseChildren(final boolean closeChildren) { this.closeChildren = closeChildren; } /** * Flush all child handlers. */ @Override public void flush() { for (Handler handler : handlers) try { handler.flush(); } catch (Exception ex) { reportError("Failed to flush child handler", ex, ErrorManager.FLUSH_FAILURE); } catch (Throwable ignored) {} } /** * Close all child handlers. */ @Override public void close() throws SecurityException { if (closeChildren) { for (Handler handler : handlers) try { handler.close(); } catch (Exception ex) { reportError("Failed to close child handler", ex, ErrorManager.CLOSE_FAILURE); } catch (Throwable ignored) { } } } @Override public void setFormatter(final Formatter newFormatter) throws SecurityException { super.setFormatter(newFormatter); } @Override public void setFilter(final Filter newFilter) throws SecurityException { super.setFilter(newFilter); } @Override public void setEncoding(final String encoding) throws SecurityException, UnsupportedEncodingException { super.setEncoding(encoding); } @Override public void setErrorManager(final ErrorManager em) { super.setErrorManager(em); } @Override public void setLevel(final Level newLevel) throws SecurityException { super.setLevel(newLevel); } /** * Indicates whether or not the {@linkplain #getFormatter() formatter} associated with this handler or a formatter * from a {@linkplain #getHandlers() child handler} requires the caller to be calculated. *

* Calculating the caller on a {@linkplain ExtLogRecord log record} can be an expensive operation. Some handlers * may be required to copy some data from the log record, but may not need the caller information. If the * {@linkplain #getFormatter() formatter} is a {@link ExtFormatter} the * {@link ExtFormatter#isCallerCalculationRequired()} is used to determine if calculation of the caller is * required. *

* * @return {@code true} if the caller should be calculated, otherwise {@code false} if it can be skipped * * @see LogRecord#getSourceClassName() * @see ExtLogRecord#getSourceFileName() * @see ExtLogRecord#getSourceLineNumber() * @see LogRecord#getSourceMethodName() */ @SuppressWarnings("WeakerAccess") public boolean isCallerCalculationRequired() { Formatter formatter = getFormatter(); if (formatterRequiresCallerCalculation(formatter)) { return true; } else for (Handler handler : getHandlers()) { if (handler instanceof ExtHandler) { if (((ExtHandler) handler).isCallerCalculationRequired()) { return true; } } else { formatter = handler.getFormatter(); if (formatterRequiresCallerCalculation(formatter)) { return true; } } } return false; } @Override protected void reportError(String msg, Exception ex, int code) { super.reportError(msg, ex, code); } /** * Report an error using a handler's specific error manager, if any. * * @param handler the handler * @param msg the error message * @param ex the exception * @param code the error code */ public static void reportError(Handler handler, String msg, Exception ex, int code) { if (handler != null) { ErrorManager errorManager = handler.getErrorManager(); if (errorManager != null) try { errorManager.error(msg, ex, code); } catch (Exception ex2) { // use the same message as the JDK System.err.println("Handler.reportError caught:"); ex2.printStackTrace(); } } } private static boolean formatterRequiresCallerCalculation(final Formatter formatter) { return formatter != null && (!(formatter instanceof ExtFormatter) || ((ExtFormatter) formatter).isCallerCalculationRequired()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy