отдельный регистратор для каждого экземпляра библиотеки - PullRequest
6 голосов
/ 13 декабря 2011

У нас есть простая старая библиотека java, которая создается из множества различных приложений.В этом случае каждое приложение является веб-приложением, которое находится в одном контейнере Tomcat.

Каждое приложение регистрируется в своем собственном файле журнала, используя собственный регистратор.Мы хотим, чтобы журналы, сгенерированные библиотекой, относящиеся к конкретному приложению, также отправлялись в отдельный файл журнала этих приложений.

Для этого один из способов - разрешить приложению передавать свой регистратор вlibrary:

library = new library(Logger applicationsVeryOwnLogger);

И затем используйте этот регистратор, чтобы записывать все операторы в библиотеке.Однако это означает, что регистратор теперь является переменной класса в библиотеке, и каждый класс в библиотеке нуждается в ссылке на библиотеку, чтобы использовать правильный регистратор.

Есть ли лучшие способы сделать это?

Ответы [ 2 ]

3 голосов
/ 13 декабря 2011

Вы пометили свой вопрос тегом log4j, поэтому я предполагаю, что вы это используете.

Я надеюсь, что ваша библиотека использует уникальное имя пакета.

Если этов этом случае вы можете просто настроить регистратор для этого пакета.

log4j.category.my.lib.package = INFO, libFileAppender
log4j.rootLogger = INFO, rootFileAppender

При этом сообщения из вашей библиотеки будут записываться как libFileAppender , так и rootFileAppender .

Если вы не хотите, чтобы сообщения из вашей библиотеки появлялись в rootFileAppender , вы можете отключить эту аддитивность логгера, например:

log4j.category.my.lib.package = INFO, libFileAppender
log4j.additivity.my.lib.package = false
log4j.rootLogger = INFO, rootFileAppender

С этим высообщение будет отображаться только в libFileAppender

2 голосов
/ 13 декабря 2011

У нас была похожая потребность в одном из наших старых приложений.Решением, которое мы придумали, был ResourceManager, который извлекал ресурсы (Logger, файлы конфигурации и т. Д.) С помощью (context) ClassLoader.

Обычно каждое приложение, развернутое как EAR, получает свой собственный ClassLoader, и библиотека может затем просто вызвать ResourceManager.getLogger (), чтобы получить Logger, связанный с текущим потоком / приложением.Таким образом, вам не нужно передавать его при каждом вызове метода в библиотеке (это требует, чтобы вы могли изменить библиотеку, хотя).

import java.util.*;
import java.util.logging.*;

public class ResourceManager 
{
    private static final Map<ClassLoader, Map<String, Object>> resources = 
        Collections.synchronizedMap(new WeakHashMap<ClassLoader, Map<String, Object>>());
    public static final String LOGGER = Logger.class.getName();

    static
    {
        // adjust for log4j or other frameworks
        final Logger logger = Logger.getLogger("logging.default");
        logger.setLevel(Level.ALL);
        logger.addHandler(new ConsoleHandler() 
        {
            {
                setOutputStream(System.out);
                setLevel(Level.ALL);
            }
        });
        registerResource(null, LOGGER, logger);
    }

    private static ClassLoader getApplicationScope()
    {
        return Thread.currentThread().getContextClassLoader();
    }

    public static void registerResource(final String name, final Object resource)
    {
        registerResource(getApplicationScope(), name, resource);
    }

    public static synchronized void registerResource(final ClassLoader scope, final String name, final Object resource)
    {
        Map<String, Object> hm = null;
        hm = resources.get(scope);
        if (hm == null)
        {
            hm = Collections.synchronizedMap(new HashMap<String, Object>());
            resources.put(scope, hm);
        }
        hm.put(name, resource);
    }

    public static Object getResource(final String name)
    {
        for(ClassLoader scope = getApplicationScope();;scope = scope.getParent())
        {
            final Map<String, Object> hm = resources.get(scope);
            if ((hm != null) && hm.containsKey(name)) 
            {
                return hm.get(name);
            }
            if (scope == null) break;
        }
        return null;
    }

    public static void registerLogger(final Logger logger)
    {
        registerResource(LOGGER, logger);
    }

    public static Logger getLogger()
    {
        return (Logger)getResource(LOGGER);
    }       
}

Зарегистрировать регистратор в фазе инициализации EJB / WebApp (необходимо зарегистрироваться перед любым вызовом getLogger):

Logger logger = Logger.getLogger([Application Logger Name]);
ResourceManager.registerLogger(logger);

Получить регистратор в библиотеке (служебный метод):

private Logger getLogger()
    {
        return ResourceManager.getLogger();     
    }

Возвращает регистратор для приложения (EAR), связанного с текущим потоком.

Не ограничивается регистраторами, он также работает для других ресурсов, которыми вы хотите поделиться.

Ограничения:

  • не будут работать, если вы упаковываете несколько приложений / EJB для развернутого EAR

  • Необходимо использовать ResourceManager и Logging libraryна том же или более высоком ClassLoader, чем библиотека и приложение.Если есть возможность связать, то подход Александера будет чище.(мы используем java.util.logging, который по умолчанию находится на уровне сервера, поэтому его подход не работает)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...