Как у вас есть общие файлы журналов под Windows? - PullRequest
7 голосов
/ 18 февраля 2012

У меня есть несколько разных процессов, и я хотел бы, чтобы они все записывали в один и тот же файл. Эти процессы выполняются в системе Windows 7. Некоторые из них являются скриптами на Python, а другие - cmd командными файлами.

В Unix вы просто хотите, чтобы все открыли файл в режиме добавления и записали его. Пока каждый процесс записывает менее PIPE_BUF байтов в одном сообщении, каждый вызов write будет гарантированно не перемежаться с любым другим.

Есть ли способ сделать это под Windows? Наивный Unix-подобный подход терпит неудачу, потому что Windows не нравится больше чем одному процессу, имеющему файл, открытый для записи за один раз по умолчанию.

Ответы [ 2 ]

11 голосов
/ 19 февраля 2012

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

Windows позволяет не более одного процесса иметь определенный файл, открытый для доступа на запись в любой момент времени. Это может быть использовано для реализации механизма блокировки на основе файлов, который гарантирует сериализацию событий между несколькими процессами. См. https://stackoverflow.com/a/9048097/1012053 и http://www.dostips.com/forum/viewtopic.php?p=12454 для некоторых примеров.

Поскольку все, что вы пытаетесь сделать, это записывать в журнал, вы можете использовать сам файл журнала в качестве блокировки. Операция журнала инкапсулируется в подпрограмму, которая пытается открыть файл журнала в режиме добавления. Если открытие не удается, процедура возвращается назад и пытается снова. После успешного открытия журнал записывается, а затем закрывается, и процедура возвращается к вызывающей стороне. Подпрограмма выполняет любую команду, переданную ей, и все, что записано на стандартный вывод в подпрограмме, перенаправляется в журнал.

Вот тестовый пакетный скрипт, который создает 5 дочерних процессов, каждый из которых записывает в файл журнала 20 раз. Записи благополучно чередуются.

@echo off
setlocal
if "%~1" neq "" goto :test

:: Initialize
set log="myLog.log"
2>nul del %log%
2>nul del "test*.marker"
set procCount=5
set testCount=10

:: Launch %procCount% processes that write to the same log
for /l %%n in (1 1 %procCount%) do start "" /b "%~f0" %%n

:wait for child processes to finish
2>nul dir /b "test*.marker" | find /c "test" | >nul findstr /x "%procCount%" || goto :wait

:: Verify log results
for /l %%n in (1 1 %procCount%) do (
  <nul set /p "=Proc %%n log count = "
  find /c "Proc %%n: " <%log%
)

:: Cleanup
del "test*.marker"
exit /b

==============================================================================
:: code below is the process that writes to the log file

:test
set instance=%1
for /l %%n in (1 1 %testCount%) do (
  call :log echo Proc %instance% says hello!
  call :log dir "%~f0"
)
echo done >"test%1.marker"
exit

:log command args...
2>nul (
  >>%log% (
    echo ***********************************************************
    echo Proc %instance%: %date% %time%
    %*
    (call ) %= This odd syntax guarantees the inner block ends with success  =%
            %= We only want to loop back and try again if redirection failed =%
  )
) || goto :log
exit /b

Вот вывод, который показывает, что все 20 записей были успешными для каждого процесса

Proc 1 log count = 20
Proc 2 log count = 20
Proc 3 log count = 20
Proc 4 log count = 20
Proc 5 log count = 20

Вы можете открыть получившийся файл "myLog.log", чтобы увидеть, как записи были безопасно перемежены. Но вывод слишком велик для размещения здесь.

Легко показать, что одновременная запись из нескольких процессов может завершиться неудачей, изменив подпрограмму: log, чтобы она не повторялась при сбое.

:log command args...
>>%log% (
  echo ***********************************************************
  echo Proc %instance%: %date% %time%
  %*
)
exit /b

Вот некоторые примеры результатов после «разрыва» процедуры: log

The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
The process cannot access the file because it is being used by another process.
Proc 1 log count = 12
Proc 2 log count = 16
Proc 3 log count = 13
Proc 4 log count = 18
Proc 5 log count = 14
2 голосов
/ 18 февраля 2012

Вы можете попробовать этот модуль Python: http://pypi.python.org/pypi/ConcurrentLogHandler

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

Я не использовал его, но узнал об этом, читая о связанной ошибке ( Issue 4749 ) в Python.

Если вы реализуете свой собственныйкод, чтобы сделать это вместо того, чтобы использовать этот модуль, убедитесь, что вы читаете об ошибке!

Вы можете использовать перенаправление вывода в Windows, как в Bash.Передайте выходные данные пакетных файлов в скрипт Python, который регистрирует через ConcurrentLogHandler.

...