You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Ivan Pedruzzi (Jira)" <ji...@apache.org> on 2022/09/02 21:03:00 UTC
[jira] [Created] (DAEMON-447) Allow to rotate stdout and stderr redirected logs
Ivan Pedruzzi created DAEMON-447:
------------------------------------
Summary: Allow to rotate stdout and stderr redirected logs
Key: DAEMON-447
URL: https://issues.apache.org/jira/browse/DAEMON-447
Project: Commons Daemon
Issue Type: Improvement
Components: prunsrv
Affects Versions: 1.3.1, 1.3.0
Environment: Windows 10; WIndows Server 2016
Reporter: Ivan Pedruzzi
We have a large legacy web application which makes use of System.out.println to print errors.
Our Tomcat 9 is configured to redirect stdout to file using switch --StdOut
In some peculiar conditions our web application can print a very large amount error which end up in the log file and can quickly fill the hard drive, crashing the system.
Looking at the code in prunsrv.c it is possible to implement a simple rotation policy which would limit the size of the log from stdout to a configurable number of bytes.
Piggy backing on the worker thread "eventThread", when the log file size is above a configurable threshold (new option StdOutFileMaxSize) we could make a copy of the log and truncate the file.
To enable the rotation for the redirects, we would need 2 options:
--Rotate <Interval in seconds for checking the file size>
--StdOutFileMaxSize <Max number of bytes for the log file size>
These could be used for both stderr and stdout or split in dedicated options
Here is the worked altered with my change. In my local tests it behaves as I expect.
DWORD WINAPI eventThread(LPVOID lpParam)
{
DWORD dwRotateCnt = SO_LOGROTATE;
for (;;) {
DWORD dw = WaitForSingleObject(gSignalEvent, 1000);
if (dw == WAIT_TIMEOUT) {
/* Do process maintenance */
if (SO_LOGROTATE != 0 && --dwRotateCnt == 0) {
/* Perform log rotation. */
/* START CHANGE */
__int64 MAX_Mbytes = SO_STDOUTFILEMAXSIZE;
struct _stat64 fileInfo;
if (gStdwrap.szStdOutFilename
&& gStdwrap.fpStdOutFile
&& _fstat64(_fileno(gStdwrap.fpStdOutFile), &fileInfo) == 0
&& fileInfo.st_size > MAX_Mbytes) {
WCHAR sPath[SIZ_PATHLEN];
lstrlcpyW(sPath, MAX_PATH, gStdwrap.szStdOutFilename);
lstrlcatW(sPath, SIZ_PATHMAX, L"-backup.log");
//Make a copy of current log before truncating it
CopyFileW(gStdwrap.szStdOutFilename, sPath, FALSE);
//close current handle
fclose(gStdwrap.fpStdOutFile);
//re-open file to truncate it
FILE* tempHandle = _wfsopen(gStdwrap.szStdOutFilename, L"w", _SH_DENYNO);
fclose(tempHandle);
//re-open in append mode
gStdwrap.fpStdOutFile = _wfsopen(gStdwrap.szStdOutFilename, L"a", _SH_DENYNO);
_dup2(_fileno(gStdwrap.fpStdOutFile), 1);
*stdout = *(gStdwrap.fpStdOutFile);
}
/* END CHANGE */
dwRotateCnt = SO_LOGROTATE;
}
continue;
}
if (dw == WAIT_OBJECT_0 && gSignalValid) {
if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)) {
/* Invoke Thread dump */
if (gWorker && _jni_startup)
apxJavaDumpAllStacks(gWorker);
}
ResetEvent(gSignalEvent);
continue;
}
break;
}
ExitThread(0);
return 0;
UNREFERENCED_PARAMETER(lpParam);
}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)