Filehandler java не создает файл
The FileHandler can either write to a specified file, or it can write to a rotating set of files.
For a rotating set of files, as each file reaches a given size limit, it is closed, rotated out, and a new file opened. Successively older files are named by adding "0", "1", "2", etc. into the base filename.
By default buffering is enabled in the IO libraries but each log record is flushed out when it is complete.
By default the XMLFormatter class is used for formatting.
- .level specifies the default level for the Handler (defaults to Level.ALL ).
- .filter specifies the name of a Filter class to use (defaults to no Filter ).
- .formatter specifies the name of a Formatter class to use (defaults to java.util.logging.XMLFormatter )
- .encoding the name of the character set encoding to use (defaults to the default platform encoding).
- .limit specifies an approximate maximum amount to write (in bytes) to any one file. If this is zero, then there is no limit. (Defaults to no limit).
- .count specifies how many output files to cycle through (defaults to 1).
- .pattern specifies a pattern for generating the output file name. See below for details. (Defaults to "%h/java%u.log").
- .append specifies whether the FileHandler should append onto any existing files (defaults to false).
- .maxLocks specifies the maximum number of concurrent locks held by FileHandler (defaults to 100).
- java.util.logging.FileHandler.level=INFO
- java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
- com.foo.MyHandler.level=INFO
- com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter
- "/" the local pathname separator
- "%t" the system temporary directory
- "%h" the value of the "user.home" system property
- "%g" the generation number to distinguish rotated logs
- "%u" a unique number to resolve conflicts
- "%%" translates to a single percent sign "%"
Thus for example a pattern of "%t/java%g.log" with a count of 2 would typically cause log files to be written on Solaris to /var/tmp/java0.log and /var/tmp/java1.log whereas on Windows 95 they would be typically written to C:\TEMP\java0.log and C:\TEMP\java1.log
Generation numbers follow the sequence 0, 1, 2, etc.
Normally the "%u" unique field is set to 0. However, if the FileHandler tries to open the filename and finds the file is currently in use by another process it will increment the unique number field and try again. This will be repeated until FileHandler finds a file name that is not currently in use. If there is a conflict and no "%u" field has been specified, it will be added at the end of the filename after a dot. (This will be after any automatically added generation number.)
Thus if three processes were all trying to log to fred%u.%g.txt then they might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as the first file in their rotating sequences.
Note that the use of unique ids to avoid conflicts is only guaranteed to work reliably when using a local disk file system.
Этот тестовый код создает в Java 7 только один файл «test_0_0.log», независимо от того, как часто я запускаю программу. Это ожидаемое поведение, поскольку для параметра добавления в конструкторе установлено значение true.
Но если я запускаю этот образец на Java 8, каждый запуск создает новый файл (test_0_0.log, test_0_1.log, test_0_2.log, . ). Я считаю это ошибкой.
Имхо, связанное с этим изменение в Java следующее:
Я знаю, что обычно FileHandler закрывается Logmanager, но это не так, если происходит сбой системы или приложения или процесс прекращается. Вот почему у меня нет оператора «закрыть» в приведенном выше примере кода.
Теперь у меня два вопроса:
1) Каково ваше мнение? Это ошибка? (Почти ответил в следующих комментариях и ответах)
2) Знаете ли вы обходной путь, чтобы получить старое поведение Java 7 в Java 8? (Более важный вопрос . )
Спасибо за ответы.
@laune: Привет, в данном примере это не имеет значения. Если я не вызываю «закрыть», файл «.lck» останется после остановки приложения, но дело не в этом, потому что это также может произойти при сбое приложения или всей системы. В Java 7 Filehandler обнаруживает в этом случае существующий lck-File и проверяет, может ли он заблокировать его. В противном случае файл используется другим процессом, и значение счетчика% u увеличивается, но если да, он считает этот файл пережитком предыдущего, больше не запущенного процесса и использует существующий файл блокировки.
@laune: Но в Java 8 само существование файла блокировки приводит к увеличению счетчика% u. И, как уже было сказано, это (существование файла lck) также могло быть вызвано сбоем системы.
1 ответ
Закрытие FileHandler удаляет файл lck. Если файл блокировки вообще существует в версии JDK8, меньше обновления 40 (java.util.logging), FileHandler будет вращаться. Из обсуждения OpenJDK было принято решение всегда чередовать, если файл lck существует, в дополнение к тому, если текущий процесс не может его заблокировать. Причина в том, что всегда безопаснее вращать, когда файл блокировки существует. Так что это становится действительно неприятным, если у вас есть вращающийся шаблон, используемый со смесью версий JDK, потому что версия JDK7 будет повторно использовать блокировку, но версия JDK8 оставит ее и повернется. Это то, что вы делаете со своим тестовым примером.
Используя JDK8, если я очищаю все файлы журнала и lck из рабочего каталога, а затем запускаю:
Я всегда вижу файл с именем test_0.log.0. Я получаю тот же результат, используя JDK7.
Суть в том, что вы должны убедиться, что ваши FileHandler закрыты. Если он никогда не был собран с мусором или удален из дерева регистратора, то LogManager закроется ваш FileHandler. В противном случае вам придется закрыть его. После того, как это будет исправлено, очистите все файлы блокировки перед запуском нового исправленного кода. Тогда имейте в виду, что если процесс JVM упадет или будет убит, файл блокировки не будет удален. Если при закрытии возникает ошибка ввода-вывода, ваш файл блокировки не будет удален. Когда запускается следующий процесс, FileHandler будет вращаться.
Как вы указываете, можно использовать все файлы блокировки на JDK8, если указанные выше условия выполняются после 100 запусков. Простой тест для этого - дважды запустить следующий код, не удаляя файлы журнала и lck:
Однако приведенный выше тестовый пример не будет работать, если JDK-6774110 исправлен. правильно. Проблема для этого может быть отслежена на сайте OpenJDK по адресу RFR: 8048020 - Регрессия в java.util.logging.FileHandler и FileHandler webrev.
Конечно, если вы закроете FileHandler, файл lck будет удален, и все будет в порядке. Но есть много причин, по которым никогда не вызывается оператор "close": сбой системы или приложения, завершение процесса . И эти файлы останутся навсегда (если вы не очистите их вручную). Еще хуже: после того, как существует 100 файлов lck, вы больше не можете запускать приложение, потому что жестко запрограммировано максимум 100 файлов lck, и если это достигается, генерируется непроверенное исключение.
Дело в том, что я не понимаю, почему новое поведение должно быть лучше старого. В моих тестах с Java 7 блокировки от других jvms / процессов распознаются правильно. А реальное поведение - это бомба замедленного действия.
The FileHandler can either write to a specified file, or it can write to a rotating set of files.
For a rotating set of files, as each file reaches a given size limit, it is closed, rotated out, and a new file opened. Successively older files are named by adding "0", "1", "2", etc. into the base filename.
By default buffering is enabled in the IO libraries but each log record is flushed out when it is complete.
By default the XMLFormatter class is used for formatting.
- .level specifies the default level for the Handler (defaults to Level.ALL).
- .filter specifies the name of a Filter class to use (defaults to no Filter).
- .formatter specifies the name of a Formatter class to use (defaults to java.util.logging.XMLFormatter)
- .encoding the name of the character set encoding to use (defaults to the default platform encoding).
- .limit specifies an approximate maximum amount to write (in bytes) to any one file. If this is zero, then there is no limit. (Defaults to no limit).
- .count specifies how many output files to cycle through (defaults to 1).
- .pattern specifies a pattern for generating the output file name. See below for details. (Defaults to "%h/java%u.log").
- .append specifies whether the FileHandler should append onto any existing files (defaults to false).
- java.util.logging.FileHandler.level=INFO
- java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
- com.foo.MyHandler.level=INFO
- com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter
- "/" the local pathname separator
- "%t" the system temporary directory
- "%h" the value of the "user.home" system property
- "%g" the generation number to distinguish rotated logs
- "%u" a unique number to resolve conflicts
- "%%" translates to a single percent sign "%"
Thus for example a pattern of "%t/java%g.log" with a count of 2 would typically cause log files to be written on Solaris to /var/tmp/java0.log and /var/tmp/java1.log whereas on Windows 95 they would be typically written to C:\TEMP\java0.log and C:\TEMP\java1.log
Generation numbers follow the sequence 0, 1, 2, etc.
Normally the "%u" unique field is set to 0. However, if the FileHandler tries to open the filename and finds the file is currently in use by another process it will increment the unique number field and try again. This will be repeated until FileHandler finds a file name that is not currently in use. If there is a conflict and no "%u" field has been specified, it will be added at the end of the filename after a dot. (This will be after any automatically added generation number.)
Thus if three processes were all trying to log to fred%u.%g.txt then they might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as the first file in their rotating sequences.
Note that the use of unique ids to avoid conflicts is only guaranteed to work reliably when using a local disk file system.
The FileHandler can either write to a specified file, or it can write to a rotating set of files.
For a rotating set of files, as each file reaches a given size limit, it is closed, rotated out, and a new file opened. Successively older files are named by adding "0", "1", "2", etc. into the base filename.
By default buffering is enabled in the IO libraries but each log record is flushed out when it is complete.
By default the XMLFormatter class is used for formatting.
- .level specifies the default level for the Handler (defaults to Level.ALL ).
- .filter specifies the name of a Filter class to use (defaults to no Filter ).
- .formatter specifies the name of a Formatter class to use (defaults to java.util.logging.XMLFormatter )
- .encoding the name of the character set encoding to use (defaults to the default platform encoding).
- .limit specifies an approximate maximum amount to write (in bytes) to any one file. If this is zero, then there is no limit. (Defaults to no limit).
- .count specifies how many output files to cycle through (defaults to 1).
- .pattern specifies a pattern for generating the output file name. See below for details. (Defaults to "%h/java%u.log").
- .append specifies whether the FileHandler should append onto any existing files (defaults to false).
- .maxLocks specifies the maximum number of concurrent locks held by FileHandler (defaults to 100).
- java.util.logging.FileHandler.level=INFO
- java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
- com.foo.MyHandler.level=INFO
- com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter
- "/" the local pathname separator
- "%t" the system temporary directory
- "%h" the value of the "user.home" system property
- "%g" the generation number to distinguish rotated logs
- "%u" a unique number to resolve conflicts
- "%%" translates to a single percent sign "%"
Thus for example a pattern of "%t/java%g.log" with a count of 2 would typically cause log files to be written on Solaris to /var/tmp/java0.log and /var/tmp/java1.log whereas on Windows 95 they would be typically written to C:\TEMP\java0.log and C:\TEMP\java1.log
Generation numbers follow the sequence 0, 1, 2, etc.
Normally the "%u" unique field is set to 0. However, if the FileHandler tries to open the filename and finds the file is currently in use by another process it will increment the unique number field and try again. This will be repeated until FileHandler finds a file name that is not currently in use. If there is a conflict and no "%u" field has been specified, it will be added at the end of the filename after a dot. (This will be after any automatically added generation number.)
Thus if three processes were all trying to log to fred%u.%g.txt then they might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as the first file in their rotating sequences.
Note that the use of unique ids to avoid conflicts is only guaranteed to work reliably when using a local disk file system.
Пример вызова регистратора:
Я попытался выполнить ваш код и получить следующий вывод как в консоли, так и в файле:
Это означает, что ваш код не виноват, поэтому вы можете попробовать следующее:
Убедитесь, что следующий код правильно выводится на консоль:
Если первый тест не выводит что-либо на консоль, прочитайте следующий документ, где вы можете найти список распространенных причин, по которым Java регистратор не работает, и конкретные шаги по их устранению (по крайней мере, связанные с конфигурацией) :
В том-то и проблема, что logger.info("Это тест") вообще не выводит на консоль. Файл не в режиме только для чтения, и FileWriter правильно пишет на лету. Кажется, что по какой-то причине java.util.logging не включен.
@JulianG.M.I обновил ответ ссылкой на документ, который может помочь вам понять, почему регистратор Java не печатает. Ваш следующий шаг должен состоять в том, чтобы прочитать этот связанный документ и убедиться, что вы не используете какие-либо аргументы JVM, такие как указание местоположения конфигурации регистратора.
Я не смог заставить свой Logger работать после нескольких часов расследования. По-видимому, это может быть вызвано операцией reset(), выполняемой какой-либо библиотекой.
Я знаю, что это не то, о чем вы изначально спрашивали, но рассматривали ли вы возможность использования Log4j вместо родного Java Logger? Я лично использую его и думаю, что он намного лучше, чем регистратор Java. Может быть, вам больше повезет с этим.
Из кода вы используете относительный путь Logs/LogFsForensics.log Это означает, что если текущий рабочий каталог, если процесс изменит путь, будет недействительным. Когда это произойдет, FileHandler создаст файл в расположении по умолчанию . Используйте абсолютный путь или укажите один из специальных компонентов FileHandler . Например:
/Logs/LogFsForensics.log как абсолютный путь или %h/Logs/LogFsForensics.log как относительный из домашнего каталога.
Вы можете изменить тестовую программу из журнала, не отображающего, чтобы распечатать дерево регистратора и обработчики. Возможно не правильно выставлены уровни или не был установлен обработчик.
Глядя на код, я бы подумал, что вы хотите getInstance синхронизироваться, чтобы никогда не пытаться создать более одного обработчика.
Читайте также: