com.caucho.log.EnvironmentLogger Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.log;
import com.caucho.loader.ClassLoaderListener;
import com.caucho.loader.DynamicClassLoader;
import com.caucho.loader.Environment;
import com.caucho.loader.EnvironmentClassLoader;
import com.caucho.loader.EnvironmentLocal;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
/**
* Proxy logger that understands the environment.
*/
class EnvironmentLogger extends Logger implements ClassLoaderListener {
private static final Handler[] EMPTY_HANDLERS = new Handler[0];
private static ClassLoader _systemClassLoader;
// The custom local handlers
private final EnvironmentLocal _localLoggers
= new EnvironmentLocal();
// The environment handlers for the Logger
private final EnvironmentLocal _localHandlers
= new EnvironmentLocal();
// The environment handlers owned by the Logger
private final EnvironmentLocal _ownHandlers
= new EnvironmentLocal();
// The use-parent-handlers value
private final EnvironmentLocal _useParentHandlers
= new EnvironmentLocal();
// Application level override
private EnvironmentLocal _localLevel;
private Level _systemLevel = null;
private EnvironmentLogger _parent;
// Can be a weak reference because any configuration in an
// environment will be held in the EnvironmentLocal.
private final ArrayList> _children
= new ArrayList>();
// Weak list of all the class loaders
private final ArrayList> _loaders
= new ArrayList>();
// The local effective level
private EnvironmentLocal _localEffectiveLevel;
private boolean _hasLocalEffectiveLevel;
private Level _finestEffectiveLevel = Level.INFO;
private int _finestEffectiveLevelValue = _finestEffectiveLevel.intValue();
private int _systemEffectiveLevelValue = Level.INFO.intValue();
public EnvironmentLogger(String name, String resourceBundleName)
{
super(name, resourceBundleName);
}
/**
* Sets the logger's parent. This should only be called by the LogManager
* code.
*/
@Override
public void setParent(Logger parent)
{
if (parent.equals(_parent))
return;
super.setParent(parent);
if (parent instanceof EnvironmentLogger) {
_parent = (EnvironmentLogger) parent;
_parent.addChild(this);
}
updateEffectiveLevel(_systemClassLoader);
}
//
// levels
//
/**
* Returns the logger's assigned level.
*/
@Override
public Level getLevel()
{
if (_localLevel != null) {
Level level = _localLevel.get();
if (level != null) {
return level;
}
}
return _systemLevel;
}
/**
* Application API to set the level.
*
* @param level the logging level to set for the logger.
*/
@Override
public void setLevel(Level level)
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null)
loader = _systemClassLoader;
if (loader != _systemClassLoader) {
if (_localLevel == null)
_localLevel = new EnvironmentLocal();
_localLevel.set(level);
if (level != null) {
addLoader(loader);
}
}
else {
_systemLevel = level;
}
updateEffectiveLevel(loader);
}
//
// handlers
//
/**
* Returns the handlers.
*/
@Override
public Handler []getHandlers()
{
Handler []handlers = _localHandlers.get();
if (handlers != null)
return handlers;
else
return EMPTY_HANDLERS;
}
/**
* Adds a handler.
*/
@Override
public void addHandler(Handler handler)
{
synchronized (this) {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null)
loader = _systemClassLoader;
boolean hasLoader = false;
for (int i = _loaders.size() - 1; i >= 0; i--) {
WeakReference ref = _loaders.get(i);
ClassLoader refLoader = ref.get();
if (refLoader == null)
_loaders.remove(i);
if (refLoader == loader)
hasLoader = true;
if (isParentLoader(loader, refLoader))
addHandler(handler, refLoader);
}
if (! hasLoader) {
_loaders.add(new WeakReference(loader));
addHandler(handler, loader);
Environment.addClassLoaderListener(this, loader);
}
HandlerEntry ownHandlers = _ownHandlers.get();
if (ownHandlers == null) {
ownHandlers = new HandlerEntry(this);
_ownHandlers.set(ownHandlers);
}
ownHandlers.addHandler(handler);
}
}
/**
* Removes a handler.
*/
@Override
public void removeHandler(Handler handler)
{
synchronized (this) {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null)
loader = _systemClassLoader;
for (int i = _loaders.size() - 1; i >= 0; i--) {
WeakReference ref = _loaders.get(i);
ClassLoader refLoader = ref.get();
if (refLoader == null)
_loaders.remove(i);
if (isParentLoader(loader, refLoader))
removeHandler(handler, refLoader);
}
HandlerEntry ownHandlers = _ownHandlers.get();
if (ownHandlers != null)
ownHandlers.removeHandler(handler);
}
}
//
// logging
//
/**
* True if the level is loggable
*/
@Override
public final boolean isLoggable(Level level)
{
if (level == null)
return false;
int intValue = level.intValue();
if (intValue < _finestEffectiveLevelValue)
return false;
else if (! _hasLocalEffectiveLevel) {
return true;
}
else {
Integer localValue = _localEffectiveLevel.get();
if (localValue != null) {
int localIntValue = localValue.intValue();
if (localIntValue == Level.OFF.intValue())
return false;
else
return localIntValue <= intValue;
}
else {
if (_systemEffectiveLevelValue == Level.OFF.intValue())
return false;
else
return _systemEffectiveLevelValue <= intValue;
}
}
}
/**
* Returns the use-parent-handlers
*/
@Override
public boolean getUseParentHandlers()
{
Boolean value = _useParentHandlers.get();
if (value != null)
return Boolean.TRUE.equals(value);
else
return true;
}
/**
* Sets the use-parent-handlers
*/
@Override
public void setUseParentHandlers(boolean useParentHandlers)
{
_useParentHandlers.set(new Boolean(useParentHandlers));
}
/**
* Logs the message.
*/
@Override
public void log(LogRecord record)
{
if (record == null)
return;
Level recordLevel = record.getLevel();
if (! isLoggable(recordLevel)) {
return;
}
for (Logger ptr = this; ptr != null; ptr = ptr.getParent()) {
Handler handlers[] = ptr.getHandlers();
if (handlers != null) {
for (int i = 0; i < handlers.length; i++) {
handlers[i].publish(record);
}
}
if (! ptr.getUseParentHandlers())
break;
}
}
//
// implementation methods
//
/**
* Adds a new logger as a child, triggered by a setParent.
*/
void addChild(EnvironmentLogger child)
{
_children.add(new WeakReference(child));
updateChildren();
}
/**
* Adds a new handler with a given classloader context.
*/
private void addHandler(Handler handler, ClassLoader loader)
{
// handlers ordered by level
ArrayList handlers = new ArrayList();
handlers.add(handler);
for (ClassLoader ptr = loader; ptr != null; ptr = ptr.getParent()) {
Handler []localHandlers = _localHandlers.getLevel(ptr);
if (localHandlers != null) {
for (int i = 0; i < localHandlers.length; i++) {
int p = handlers.indexOf(localHandlers[i]);
if (p < 0) {
handlers.add(localHandlers[i]);
}
else {
Handler oldHandler = handlers.get(p);
if (localHandlers[i].getLevel().intValue()
< oldHandler.getLevel().intValue()) {
handlers.set(p, localHandlers[i]);
}
}
}
}
}
Handler []newHandlers = new Handler[handlers.size()];
handlers.toArray(newHandlers);
if (loader == _systemClassLoader)
loader = null;
_localHandlers.set(newHandlers, loader);
}
private void removeHandler(Handler handler, ClassLoader loader)
{
ArrayList handlers = new ArrayList();
for (ClassLoader ptr = loader; ptr != null; ptr = ptr.getParent()) {
Handler []localHandlers = _localHandlers.getLevel(ptr);
if (localHandlers != null) {
for (int i = 0; i < localHandlers.length; i++) {
if (! localHandlers[i].equals(handler)) {
int p = handlers.indexOf(localHandlers[i]);
if (p < 0) {
handlers.add(localHandlers[i]);
}
else {
Handler oldHandler = handlers.get(p);
if (localHandlers[i].getLevel().intValue()
< oldHandler.getLevel().intValue()) {
handlers.set(p, localHandlers[i]);
}
}
}
}
}
}
Handler []newHandlers = new Handler[handlers.size()];
handlers.toArray(newHandlers);
_localHandlers.set(newHandlers, loader);
}
/**
* Returns true if 'parent' is a parent classloader of 'child'.
*
* @param parent the classloader to test as a parent.
* @param child the classloader to test as a child.
*/
private boolean isParentLoader(ClassLoader parent, ClassLoader child)
{
for (; child != null; child = child.getParent()) {
if (child == parent)
return true;
}
return false;
}
/**
* Sets a custom logger if possible
*/
boolean addCustomLogger(Logger logger)
{
if (logger.getClass().getName().startsWith("java"))
return false;
Logger oldLogger = _localLoggers.get();
if (oldLogger != null)
return false;
_localLoggers.set(logger);
if (_parent != null) {
logger.setParent(_parent);
}
return true;
}
/**
* Gets the custom logger if possible
*/
Logger getLogger()
{
return _localLoggers.get();
}
/**
* Adds a class loader to the list of dependency loaders.
*/
private void addLoader(ClassLoader loader)
{
for (int i = _loaders.size() - 1; i >= 0; i--) {
WeakReference ref = _loaders.get(i);
ClassLoader refLoader = ref.get();
if (refLoader == null)
_loaders.remove(i);
if (refLoader == loader)
return;
}
_loaders.add(new WeakReference(loader));
Environment.addClassLoaderListener(this, loader);
}
/**
* Returns the assigned level, calculated through the normal
* Logger rules, i.e. if unassigned, use the parent's value.
*/
/*
private Level getAssignedLevel()
{
for (Logger log = this; log != null; log = log.getParent()) {
Level level = log.getLevel();
if (level != null)
return level;
}
return Level.INFO;
}
*/
/**
* Recalculate the dynamic assigned levels.
*/
private synchronized void updateEffectiveLevel(ClassLoader loader)
{
if (loader == null)
loader = _systemClassLoader;
int oldEffectiveLevel = getEffectiveLevel(loader);
Level newEffectiveLevel = calculateEffectiveLevel(loader);
/*
if (loader == _systemClassLoader) {
_finestEffectiveLevel = newEffectiveLevel;
_finestEffectiveLevelValue = newEffectiveLevel.intValue();
super.setLevel(_finestEffectiveLevel);
}
*/
if (oldEffectiveLevel == newEffectiveLevel.intValue()
&& loader != _systemClassLoader)
return;
_finestEffectiveLevel = newEffectiveLevel;
_hasLocalEffectiveLevel = false;
updateEffectiveLevelPart(_systemClassLoader);
updateEffectiveLevelPart(loader);
for (int i = 0; i < _loaders.size(); i++) {
WeakReference loaderRef = _loaders.get(i);
ClassLoader classLoader = loaderRef.get();
if (classLoader != null)
updateEffectiveLevelPart(classLoader);
}
super.setLevel(_finestEffectiveLevel);
_finestEffectiveLevelValue = _finestEffectiveLevel.intValue();
updateChildren();
}
private void updateChildren()
{
updateChildren(_systemClassLoader);
for (int i = _loaders.size() - 1; i >= 0; i--) {
WeakReference loaderRef = _loaders.get(i);
ClassLoader subLoader = loaderRef.get();
if (subLoader != null)
updateChildren(subLoader);
else
_loaders.remove(i);
}
}
private void updateEffectiveLevelPart(ClassLoader loader)
{
Level level = getOwnEffectiveLevel(loader);
if (loader == _systemClassLoader) {
_systemEffectiveLevelValue
= (level != null ? level.intValue() : Level.INFO.intValue());
}
if (level == null) {
if (_localEffectiveLevel != null)
_localEffectiveLevel.remove(loader);
return;
}
if (_finestEffectiveLevel == null)
_finestEffectiveLevel = level;
else if (level.intValue() < _finestEffectiveLevel.intValue()) {
_finestEffectiveLevel = level;
}
if (loader == _systemClassLoader) {
_systemEffectiveLevelValue = level.intValue();
}
else {
_hasLocalEffectiveLevel = true;
addLoader(loader);
if (_localEffectiveLevel == null)
_localEffectiveLevel = new EnvironmentLocal();
_localEffectiveLevel.set(level.intValue(), loader);
}
}
private Level getOwnEffectiveLevel(ClassLoader loader)
{
Level level = null;
if (loader == _systemClassLoader) {
level = _systemLevel;
}
else if (_localLevel != null) {
level = _localLevel.getLevel(loader);
}
if (level != null)
return level;
else if (_parent != null)
return _parent.getOwnEffectiveLevel(loader);
else
return null;
}
private int getEffectiveLevel(ClassLoader loader)
{
int oldEffectiveLevel = _systemEffectiveLevelValue;
if (_localEffectiveLevel != null) {
Integer intLevel = _localEffectiveLevel.get(loader);
if (intLevel != null)
oldEffectiveLevel = intLevel;
}
return oldEffectiveLevel;
}
private Level calculateEffectiveLevel(ClassLoader loader)
{
Level level = getLevel(loader);
if (level != null)
return level;
else if (_parent != null)
return _parent.calculateEffectiveLevel(loader);
else
return Level.INFO;
}
private Level getLevel(ClassLoader loader)
{
if (_localLevel != null) {
Level level = _localLevel.get(loader);
if (level != null) {
return level;
}
}
return _systemLevel;
}
/**
* Returns the finest assigned level for any classloader environment.
*/
private Level getFinestLevel()
{
Level level;
if (_parent == null)
level = Level.INFO;
else if (_parent.isLocalLevel())
level = selectFinestLevel(_systemLevel, _parent.getFinestLevel());
else if (_systemLevel != null)
level = _systemLevel;
else
level = _parent.getFinestLevel();
if (_localLevel == null)
return level;
for (int i = _loaders.size() - 1; i >= 0; i--) {
WeakReference ref = _loaders.get(i);
ClassLoader loader = ref.get();
if (loader == null)
_loaders.remove(i);
level = selectFinestLevel(level, _localLevel.get(loader));
}
return level;
}
private boolean isLocalLevel()
{
if (_localLevel != null)
return false;
else if (_parent != null && ! _parent.isLocalLevel())
return false;
else
return true;
}
/**
* Returns the finest of the two levels.
*/
private Level selectFinestLevel(Level a, Level b)
{
if (a == null)
return b;
else if (b == null)
return a;
else if (b.intValue() < a.intValue())
return b;
else
return a;
}
/**
* Returns the most specific assigned level for the given classloader, i.e.
* children override parents.
*/
private Level getAssignedLevel(ClassLoader loader)
{
Level level = null;
if (_localLevel != null) {
return _localLevel.get(loader);
}
return null;
}
private void updateClassLoaderLevel(ClassLoader loader)
{
if (_localLevel == null) {
if (_systemLevel != null)
super.setLevel(_systemLevel);
return;
}
Level localLevel = _localLevel.get(loader);
if (localLevel != null) {
if (! _hasLocalEffectiveLevel)
super.setLevel(localLevel);
else if (localLevel.intValue() < super.getLevel().intValue())
super.setLevel(localLevel);
_hasLocalEffectiveLevel = true;
}
}
private void updateChildren(ClassLoader loader)
{
for (int i = _children.size() - 1; i >= 0; i--) {
WeakReference ref = _children.get(i);
EnvironmentLogger child = ref.get();
if (child != null)
child.updateEffectiveLevel(loader);
else
_children.remove(i);
}
}
/**
* Removes the specified loader.
*/
private synchronized void removeLoader(ClassLoader loader)
{
int i;
for (i = _loaders.size() - 1; i >= 0; i--) {
WeakReference ref = _loaders.get(i);
ClassLoader refLoader = ref.get();
if (refLoader == null)
_loaders.remove(i);
else if (refLoader == loader)
_loaders.remove(i);
}
}
/**
* Classloader init callback
*/
public void classLoaderInit(DynamicClassLoader env)
{
}
/**
* Classloader destroy callback
*/
@Override
public void classLoaderDestroy(DynamicClassLoader loader)
{
removeLoader(loader);
_localHandlers.remove(loader);
HandlerEntry ownHandlers = _ownHandlers.getLevel(loader);
if (ownHandlers != null)
_ownHandlers.remove(loader);
if (ownHandlers != null)
ownHandlers.destroy();
if (_localLevel != null)
_localLevel.remove(loader);
updateEffectiveLevel(_systemClassLoader);
}
@Override
public String toString()
{
return "EnvironmentLogger[" + getName() + "]";
}
/**
* Encapsulates the handler for this logger, keeping a reference in
* the local environment to avoid GC.
*/
static class HandlerEntry {
private final EnvironmentLogger _logger;
private ArrayList _handlers = new ArrayList();
HandlerEntry(EnvironmentLogger logger)
{
_logger = logger;
}
void addHandler(Handler handler)
{
_handlers.add(handler);
}
void removeHandler(Handler handler)
{
_handlers.remove(handler);
}
void destroy()
{
ArrayList handlers = _handlers;
_handlers = null;
for (int i = 0; handlers != null && i < handlers.size(); i++) {
Handler handler = handlers.get(i);
try {
handler.close();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
}
static {
try {
_systemClassLoader = ClassLoader.getSystemClassLoader();
} catch (Exception e) {
// too early to log
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy