Spec-Zone .ru
спецификации, руководства, описания, API
|
1.0 Краткий обзор Журналирования Java
1.1 Краткий обзор Потока управления
1.2 Уровни журнала
1.3 Регистраторы
1.4 Журналирование Методов
1.5 Обработчики
1.6 Средства форматирования
1.7 LogManager
1.8 Конфигурационный файл
1.9 Конфигурация по умолчанию
1.10 Динамических Обновления Конфигурации
1.11 Собственных Метода
1.12 DTD XML
1.13 Уникальных ID сообщения
1.14 Безопасности
1.15 управления конфигурацией
1.16 Упаковки
1.17 Локализации
1.18 Удаленных доступа и Сериализация
2.0 Примеры
2.1 Простое Использование
2.2 Изменение Конфигурации
2.3 Простое Использование, Игнорируя Глобальную Конфигурацию
2.4 Демонстрационный XML Вывод
3.0 Приложение A: DTD для Вывода XMLFormatter
API журналирования описываются подробно в Java Спецификация API SE. Цель этого документа состоит в том, чтобы обеспечить краткий обзор основных элементов.
Приложения делают запросы журналирования к объектам Регистратора. Регистраторы организуются в иерархическом пространстве имен, и дочерние Регистраторы могут наследовать некоторые свойства журналирования от своих родителей в пространстве имен.
Приложения делают запросы журналирования к объектам Регистратора. Эти объекты Регистратора выделяют объекты LogRecord, которые передают к Объектам-обработчикам для публикации. И Регистраторы и Обработчики могут использовать Уровни журналирования и (дополнительно) Фильтры, чтобы решить, интересуются ли они определенным LogRecord. Когда необходимо опубликовать LogRecord внешне, Обработчик может (дополнительно) использовать Средство форматирования, чтобы локализовать и отформатировать сообщение прежде, чем опубликовать это к потоку ввода-вывода.
Каждый Регистратор отслеживает ряд выходных Обработчиков. По умолчанию все Регистраторы также отправляют свой вывод их родительскому Регистратору. Но Регистраторы могут также быть сконфигурированы, чтобы проигнорировать Обработчики выше дерево.
Некоторые Обработчики могут направить вывод к другим Обработчикам. Например, MemoryHandler поддерживает внутренний кольцевой буфер LogRecords, и на триггерных событиях это публикует свой LogRecords через целевой Обработчик. В таких случаях любое форматирование делается последним Обработчиком в цепочке.
API структурируются так, чтобы запросы к API Регистратора могли быть дешевыми, когда журналирование отключается. Если журналирование отключается для данного уровня журнала, то Регистратор может сделать дешевый тест сравнения и возврат. Если журналирование включается для данного уровня журнала, Регистратор все еще делает все возможное минимизировать затраты прежде, чем передать LogRecord в Обработчики. В частности локализация и форматирующий (которые относительно дороги) задерживается, пока Обработчик не запрашивает их. Например, MemoryHandler может поддержать круговой буфер LogRecords, не имея необходимость платить затраты форматирования.
У каждого сообщения журнала есть связанный Уровень журнала. Уровень дает грубое руководство по важности и безотлагательности сообщения журнала. Объекты уровня журнала инкапсулируют целочисленное значение с более высокими значениями, указывающими на более высокие приоритеты.
Класс Level определяет семь стандартных уровней журнала, в пределах от САМОГО ПРЕКРАСНОГО (самый низкий приоритет, с самым низким значением) к СЕРЬЕЗНОМУ (самый высокий приоритет, с самым высоким значением).
Как утверждено ранее, клиентский код отправляет запросы журнала объектам Регистратора. Каждый регистратор отслеживает уровень журнала, что он интересуется, и отбрасывает запросы журнала, которые являются ниже этого уровня.
Регистраторы обычно являются именованными сущностями, используя разделенные от точки имена, такие как "java.awt". Пространство имен является иерархическим и управляется LogManager. Пространство имен должно обычно быть выровненное пространства имен упаковки Java, но не обязано следовать за ним по-рабски. Например, Регистратор, названный "java.awt", мог бы обработать запросы журналирования на классы в java.awt пакете, но это могло бы также обработать журналирование для классов в sun.awt, которые поддерживают видимые клиентом абстракции, определенные в java.awt пакете.
В дополнение к именованным Регистраторам также возможно создать анонимные Регистраторы, которые не появляются в совместно используемом пространстве имен. См. раздел 1.14.
Регистраторы отслеживают свои родительские регистраторы в пространстве имен журналирования. Родитель регистратора является своим самым близким существующим предком в пространстве имен журналирования. У корневого Регистратора (названный"") нет никакого родителя. Анонимным регистраторам все дают корневой регистратор как их родитель. Регистраторы могут наследовать различные атрибуты от своих родителей в пространстве имен регистратора. В частности регистратор может наследоваться:
Класс Регистратора обеспечивает большой набор методов удобства для того, чтобы генерировать сообщения журнала. Для удобства есть методы для каждого уровня журналирования, названного в честь имени уровня журналирования. Таким образом вместо того, чтобы вызвать "logger.log (Уровень. ПРЕДУПРЕЖДАЯ..." разработчик может просто вызвать метод удобства "logger.warning (..."
Есть два различных стиля журналирования методов, чтобы удовлетворить потребности различных сообществ пользователей.
Во-первых, есть методы, которые берут явное исходное имя класса и исходное имя метода. Эти методы предназначаются для разработчиков, которые хотят быть в состоянии быстро определить местоположение источника любого данного журналирования сообщения. Пример этого стиля:
void warning(String sourceClass, String sourceMethod, String msg);
Во-вторых, есть ряд методов, которые не берут явный исходный класс или исходные имена методов. Они предназначаются для разработчиков, которые хотят удобное в работе журналирование и не запрашивают детализированную исходную информацию.
void warning(String msg);
Для этого второго набора методов платформа Журналирования сделает "максимальные усилия", чтобы определить, какой класс и метод, вызванный в платформу журналирования и, добавит эту информацию в LogRecord. Однако, важно понять, что эта автоматически выведенная информация может только быть приблизительной. Последняя генерация виртуальных машин выполняет обширную оптимизацию, когда JITing и может полностью удалить стековые фреймы, лишая возможности достоверно определять местоположение класса вызова и метода.
Java SE обеспечивает следующие Обработчики:
Это довольно прямо, чтобы разработать новые Обработчики. Разработчики, требующие определенной функциональности, могут или разработать Обработчик с нуля или разделить один на подклассы из обеспеченных Обработчиков.
Как с Обработчиками, это довольно прямо, чтобы разработать новые Средства форматирования.
Есть единственный объект LogManager, который может быть получен, используя статический метод LogManager.getLogManager. Это создается во время инициализации LogManager, основанной на системном свойстве. Это свойство позволяет приложениям-контейнерам (таким как контейнеры EJB) заменять своим собственным подклассом LogManager вместо класса по умолчанию.
Конфигурация журналирования может быть инициализирована, используя конфигурационный файл журналирования, который будет считан при запуске. Этот конфигурационный файл журналирования находится в стандарте java.util. Формат свойств.
Альтернативно, конфигурация журналирования может быть инициализирована, определяя класс, который может использоваться для того, чтобы считать свойства инициализации. Этот механизм позволяет данным конфигурации быть считанными из произвольных источников, таких как LDAP, JDBC, и т.д. См. Спецификацию API LogManager для деталей.
Есть маленький набор глобальной конфигурационной информации. Это определяется в описании класса LogManager и включает список Обработчиков на корневом уровне, чтобы установить во время запуска.
Начальная конфигурация может определить уровни для определенных регистраторов. Эти уровни применяются к именованному регистратору и любым регистраторам ниже его в иерархии именования. Уровни применяются в порядке, они определяются в конфигурационном файле.
Начальная конфигурация может содержать произвольные свойства для использования Обработчиками или подсистемами, делающими журналирование. Условно эти свойства должны использовать имена, запускающиеся с имени класса обработчика или имени основного Регистратора для подсистемы.
Например, MemoryHandler использует свойство "java.util.logging. MemoryHandler.size", чтобы определить размер по умолчанию для его кольцевого буфера.
Конфигурация журналирования значения по умолчанию, которая поставляет с JRE, является только значением по умолчанию, и может быть переопределена ISV, системными администраторами, и конечными пользователями.
Конфигурация по умолчанию делает только ограниченное использование дискового пространства. Это не лавинно рассылает пользователя с информацией, но действительно удостоверяется, что всегда получило ключевую информацию об отказе.
Конфигурация по умолчанию устанавливает единственный обработчик на корневом регистраторе для того, чтобы отправить вывод консоли.
Собственный код, который хочет использовать механизмы Журналирования Java, должен выполнить нормальные вызовы JNI в API Журналирования Java.
DTD XML, используемый XMLFormatter, определяется в Приложении A.
DTD разрабатывается с" <журнал>" элемент как высокоуровневый документ. Отдельные записи журнала тогда пишутся как" <запись>" элементы.Отметьте, что в случае катастрофических отказов JVM, возможно, не возможно чисто завершить поток XMLFormatter с соответствующим закрытием </журнал>. Поэтому инструменты, которые анализируют записи журнала, должны быть подготовлены справиться с незавершенными потоками.
API Журналирования Java не оказывают прямой поддержки для уникальных ID сообщения. Те приложения или подсистемы, требующие уникальных ID сообщения, должны определить свои собственные соглашения и включать уникальные ID в строки сообщения как соответствующие.
Основное требование к защите состоит в том, что недоверяемый код не должен быть в состоянии изменить конфигурацию журналирования. Определенно, если конфигурация журналирования была установлена, чтобы зарегистрировать определенную категорию информации к определенному Обработчику, то недоверяемый код не должен быть в состоянии предотвратить или разрушить то журналирование.
Новое право доступа LoggingPermission определяется, чтобы управлять обновлениями к конфигурации журналирования.
Доверяемым приложениям дают соответствующий LoggingPermission, таким образом, они могут вызвать любой из API конфигурации журналирования. Недоверяемые апплеты являются другой историей. Недоверяемые апплеты могут создать и использовать названные Регистраторы нормальным способом, но им не позволяют изменить настройки управления журналированием, такие как добавление или удаление обработчиков, или изменение уровней журнала. Однако, недоверяемые апплеты в состоянии создать и использовать их собственные "анонимные" регистраторы, используя Logger.getAnonymousLogger. Эти анонимные Регистраторы не регистрируются в глобальном пространстве имен, и их методы не проверяются в доступе, позволяя даже недоверяемый код изменить их настройки управления журналированием.
Платформа журналирования не пытается предотвратить спуфинг. Источники журналирования вызовов не могут быть определены достоверно, так, когда LogRecord публикуется, что требования быть от определенного исходного класса и исходного метода, это может быть производство. Точно так же средства форматирования, такие как XMLFormatter не пытаются защитить себя от вложенных сообщений журнала в строках сообщения. Таким образом, имитация, LogRecord мог бы содержать набор имитации XML в его строке сообщения, чтобы заставить это смотреть, как будто была дополнительная запись XML в выводе.
Кроме того, платформа журналирования не пытается защитить себя от атак "отказ в обслуживании". Любое данное журналирование клиента может лавинно разослать платформу журналирования с бессмысленными сообщениями в попытке скрыть некоторое важное сообщение журнала.
API структурируются так, чтобы начальный набор конфигурационной информации был считан как свойства из конфигурационного файла. Конфигурационная информация может тогда быть изменена programatically запросами к различным классам журналирования и объектам.
Кроме того, есть методы на LogManager, которые позволяют конфигурационному файлу быть перечитанным. Когда это произойдет, значения конфигурационного файла переопределят любые изменения, которые были произведены programatically.
Весь класс журналирования находится в части Java * пространства имен в java.util.logging пакете.
Сообщения журнала, возможно, должны быть локализованы.
У каждого Регистратора может быть имя Пакета Ресурса, связанное с этим. Соответствующий Пакет Ресурса может использоваться, чтобы отобразиться между необработанными строками сообщения и локализованными строками сообщения.
Обычно локализация будет выполняться Средствами форматирования. Как удобство, класс средства форматирования обеспечивает formatMessage метод, который обеспечивает некоторую основную локализацию и форматирующий поддержку.
Как с большинством API платформы Java, API журналирования разрабатываются для использования в единственном адресном пространстве. Все вызовы предназначаются, чтобы быть локальными. Однако, ожидается, что некоторые Обработчики будут хотеть направить свои выходные данные к другим системам. Есть множество способов сделать это:
Некоторые Обработчики (такие как SocketHandler) могут записать данные в другие системы, используя XMLFormatter. Это обеспечивает простой, стандартный, формат обмена, который может быть проанализирован и обработан на множестве систем.
Некоторые Обработчики могут хотеть передать объекты LogRecord по RMI. Класс LogRecord поэтому сериализуем. Однако есть проблема в том, как иметь дело с параметрами LogRecord. Некоторые параметры, возможно, не сериализуемы, и другие параметры, возможно, были разработаны, чтобы сериализировать намного больше состояния, чем требуется для того, чтобы зарегистрировать. Чтобы избежать этих проблем, у класса LogRecord есть пользовательский writeObject метод, который преобразовывает параметры в строки (использующий Object.toString ()) перед выписыванием их. См. Спецификацию API LogRecord для деталей.
Большинство классов журналирования не предназначается, чтобы быть сериализуемым. И Регистраторы и Обработчики являются stateful классами, которые связываются в определенную виртуальную машину. В этом отношении они походят на java.io классы, которые также не сериализуемы.
Следующее является маленькой программой, которая выполняет журналирование, используя конфигурацию по умолчанию.
Эта программа полагается на корневые обработчики, которые были установлены LogManager, основанным на конфигурационном файле. Это создает свой собственный объект Регистратора и затем делает звонки в тот объект Регистратора сообщить о различных событиях.
package com.wombat; import java.util.logging.*; public class Nose{ // Obtain a suitable logger. private static Logger logger = Logger.getLogger("com.wombat.nose"); public static void main(String argv[]) { // Log a FINE tracing message logger.fine("doing stuff"); try{ Wombat.sneeze(); } catch (Exception ex) { // Log the exception logger.log(Level.WARNING, "trouble sneezing", ex); } logger.fine("done"); } }
Вот маленькая программа, которая динамически корректирует конфигурацию журналирования, чтобы отправить вывод определенному файлу и получить большую информацию о вомбатах. Образец "%t" означает систему временный каталог.
public static void main(String[] args) { Handler fh = new FileHandler("%t/wombat.log"); Logger.getLogger("").addHandler(fh); Logger.getLogger("com.wombat").setLevel(Level.FINEST); ... }
Вот маленькая программа, которая устанавливает ее собственный Обработчик журналирования и игнорирует глобальную конфигурацию.
package com.wombat; import java.util.logging.*; public class Nose { private static Logger logger = Logger.getLogger("com.wombat.nose"); private static FileHandler fh = new FileHandler("mylog.txt"); public static void main(String argv[]) { // Send logger output to our FileHandler. logger.addHandler(fh); // Request that every detail gets logged. logger.setLevel(Level.ALL); // Log a simple INFO message. logger.info("doing stuff"); try { Wombat.sneeze(); } catch (Exception ex) { logger.log(Level.WARNING, "trouble sneezing", ex); } logger.fine("done"); } }
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE log SYSTEM "logger.dtd"> <log> <record> <date>2000-08-23 19:21:05</date> <millis>967083665789</millis> <sequence>1256</sequence> <logger>kgh.test.fred</logger> <level>INFO</level> <class>kgh.test.XMLTest</class> <method>writeLog</method> <thread>10</thread> <message>Hello world!</message> </record> </log>
<!-- DTD used by the java.util.logging.XMLFormatter --> <!-- This provides an XML formatted log message. --> <!-- The document type is "log" which consists of a sequence of record elements --> <!ELEMENT log (record*)> <!-- Each logging call is described by a record element. --> <!ELEMENT record (date, millis, sequence, logger?, level, class?, method?, thread?, message, key?, catalog?, param*, exception?)> <!-- Date and time when LogRecord was created in ISO 8601 format --> <!ELEMENT date (#PCDATA)> <!-- Time when LogRecord was created in milliseconds since midnight January 1st, 1970, UTC. --> <!ELEMENT millis (#PCDATA)> <!-- Unique sequence number within source VM. --> <!ELEMENT sequence (#PCDATA)> <!-- Name of source Logger object. --> <!ELEMENT logger (#PCDATA)> <!-- Logging level, may be either one of the constant names from java.util.logging.Level (such as "SEVERE" or "WARNING") or an integer value such as "20". --> <!ELEMENT level (#PCDATA)> <!-- Fully qualified name of class that issued logging call, e.g. "javax.marsupial.Wombat". --> <!ELEMENT class (#PCDATA)> <!-- Name of method that issued logging call. It may be either an unqualified method name such as "fred" or it may include argument type information in parenthesis, for example "fred(int,String)". --> <!ELEMENT method (#PCDATA)> <!-- Integer thread ID. --> <!ELEMENT thread (#PCDATA)> <!-- The message element contains the text string of a log message. --> <!ELEMENT message (#PCDATA)> <!-- If the message string was localized, the key element provides the original localization message key. --> <!ELEMENT key (#PCDATA)> <!-- If the message string was localized, the catalog element provides the logger's localization resource bundle name. --> <!ELEMENT catalog (#PCDATA)> <!-- If the message string was localized, each of the param elements provides the String value (obtained using Object.toString()) of the corresponding LogRecord parameter. --> <!ELEMENT param (#PCDATA)> <!-- An exception consists of an optional message string followed by a series of StackFrames. Exception elements are used for Java exceptions and other java Throwables. --> <!ELEMENT exception (message?, frame+)> <!-- A frame describes one line in a Throwable backtrace. --> <!ELEMENT frame (class, method, line?)> <!-- an integer line number within a class's source file. --> <!ELEMENT line (#PCDATA)>