Running "nssm rotate <service>" will send user-defined service control
128 to the service, triggering a rotation of output files after the next
call to ReadFile(), regardless of the value of AppRotateBytes*.
Note that since ReadFile() is synchronous, we have no way to interrupt
it, hence there may be a significant delay before the rotation happens.
or replaced them.\r
\r
NSSM can also rotate files which hit the configured size threshold while the\r
or replaced them.\r
\r
NSSM can also rotate files which hit the configured size threshold while the\r
-service is running. To enable this feature, set AppRotateOnline to a non-zero\r
+service is running. Additionally, you can trigger an on-demand rotation by\r
+running the command\r
+\r
+ nssm rotate <servicename>\r
+\r
+On-demand rotations will happen after the next line of data is read from\r
+the managed application, regardless of the value of AppRotateBytes. Be aware\r
+that if the application is not particularly verbose the rotation may not\r
+happen for some time.\r
+\r
+To enable online and on-demand rotation, set AppRotateOnline to a non-zero\r
value.\r
\r
Note that online rotation requires NSSM to intercept the application's I/O\r
value.\r
\r
Note that online rotation requires NSSM to intercept the application's I/O\r
/* Get rotation stuff. */\r
if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
service->rotate_files = true;\r
/* Get rotation stuff. */\r
if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
service->rotate_files = true;\r
- if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_ONLINE, BM_GETCHECK, 0, 0) & BST_CHECKED) service->rotate_stdout_online = service->rotate_stderr_online = true;
+ if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_ONLINE, BM_GETCHECK, 0, 0) & BST_CHECKED) service->rotate_stdout_online = service->rotate_stderr_online = NSSM_ROTATE_ONLINE;
check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, &service->rotate_seconds);\r
check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, &service->rotate_bytes_low);\r
}\r
check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, &service->rotate_seconds);\r
check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, &service->rotate_bytes_low);\r
}\r
\r
/* Try online rotation only if a size threshold is set. */\r
logger_t *stdout_logger = 0;\r
\r
/* Try online rotation only if a size threshold is set. */\r
logger_t *stdout_logger = 0;\r
- if (service->rotate_files && service->rotate_stdout_online && size.QuadPart) {\r
+ if (service->rotate_files && service->rotate_stdout_online) {\r
stdout_logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));\r
if (stdout_logger) {\r
/* Pipe between application's stdout and our logging handle. */\r
stdout_logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));\r
if (stdout_logger) {\r
/* Pipe between application's stdout and our logging handle. */\r
stdout_logger->write_handle = stdout_handle;\r
stdout_logger->size = (__int64) size.QuadPart;\r
stdout_logger->tid_ptr = &service->stdout_tid;\r
stdout_logger->write_handle = stdout_handle;\r
stdout_logger->size = (__int64) size.QuadPart;\r
stdout_logger->tid_ptr = &service->stdout_tid;\r
+ stdout_logger->rotate_online = &service->rotate_stdout_online;\r
\r
/* Logging thread. */\r
service->stdout_thread = create_logging_thread(stdout_logger);\r
\r
/* Logging thread. */\r
service->stdout_thread = create_logging_thread(stdout_logger);\r
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, error_string(GetLastError()), 0);\r
return 4;\r
}\r
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, error_string(GetLastError()), 0);\r
return 4;\r
}\r
- service->rotate_stdout_online = false;\r
+ service->rotate_stdout_online = NSSM_ROTATE_OFFLINE;\r
}\r
\r
set_flags = true;\r
}\r
\r
set_flags = true;\r
\r
/* Try online rotation only if a size threshold is set. */\r
logger_t *stderr_logger = 0;\r
\r
/* Try online rotation only if a size threshold is set. */\r
logger_t *stderr_logger = 0;\r
- if (service->rotate_files && service->rotate_stderr_online && size.QuadPart) {\r
+ if (service->rotate_files && service->rotate_stderr_online) {\r
stderr_logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));\r
if (stderr_logger) {\r
/* Pipe between application's stderr and our logging handle. */\r
stderr_logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));\r
if (stderr_logger) {\r
/* Pipe between application's stderr and our logging handle. */\r
stderr_logger->write_handle = stderr_handle;\r
stderr_logger->size = (__int64) size.QuadPart;\r
stderr_logger->tid_ptr = &service->stderr_tid;\r
stderr_logger->write_handle = stderr_handle;\r
stderr_logger->size = (__int64) size.QuadPart;\r
stderr_logger->tid_ptr = &service->stderr_tid;\r
+ stderr_logger->rotate_online = &service->rotate_stderr_online;\r
\r
/* Logging thread. */\r
service->stderr_thread = create_logging_thread(stderr_logger);\r
\r
/* Logging thread. */\r
service->stderr_thread = create_logging_thread(stderr_logger);\r
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDERR, error_string(GetLastError()), 0);\r
return 7;\r
}\r
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDERR, error_string(GetLastError()), 0);\r
return 7;\r
}\r
- service->rotate_stderr_online = false;\r
+ service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;\r
}\r
else if (ret) continue;\r
\r
}\r
else if (ret) continue;\r
\r
- if (size + (__int64) in >= logger->size) {\r
+ if (*logger->rotate_online == NSSM_ROTATE_ONLINE_ASAP || (logger->size && size + (__int64) in >= logger->size)) {\r
/* Look for newline. */\r
unsigned long i;\r
for (i = 0; i < in; i++) {\r
/* Look for newline. */\r
unsigned long i;\r
for (i = 0; i < in; i++) {\r
size += (__int64) out;\r
\r
/* Rotate. */\r
size += (__int64) out;\r
\r
/* Rotate. */\r
+ *logger->rotate_online = NSSM_ROTATE_ONLINE;\r
TCHAR rotated[MAX_PATH];\r
rotated_filename(logger->path, rotated, _countof(rotated), 0);\r
\r
TCHAR rotated[MAX_PATH];\r
rotated_filename(logger->path, rotated, _countof(rotated), 0);\r
\r
HANDLE write_handle;\r
__int64 size;\r
unsigned long *tid_ptr;\r
HANDLE write_handle;\r
__int64 size;\r
unsigned long *tid_ptr;\r
+ unsigned long *rotate_online;\r
} logger_t;\r
\r
int get_createfile_parameters(HKEY, TCHAR *, TCHAR *, unsigned long *, unsigned long, unsigned long *, unsigned long, unsigned long *, unsigned long);\r
} logger_t;\r
\r
int get_createfile_parameters(HKEY, TCHAR *, TCHAR *, unsigned long *, unsigned long, unsigned long *, unsigned long, unsigned long *, unsigned long);\r
if (str_equiv(argv[1], _T("pause"))) exit(control_service(SERVICE_CONTROL_PAUSE, argc - 2, argv + 2));\r
if (str_equiv(argv[1], _T("continue"))) exit(control_service(SERVICE_CONTROL_CONTINUE, argc - 2, argv + 2));\r
if (str_equiv(argv[1], _T("status"))) exit(control_service(SERVICE_CONTROL_INTERROGATE, argc - 2, argv + 2));\r
if (str_equiv(argv[1], _T("pause"))) exit(control_service(SERVICE_CONTROL_PAUSE, argc - 2, argv + 2));\r
if (str_equiv(argv[1], _T("continue"))) exit(control_service(SERVICE_CONTROL_CONTINUE, argc - 2, argv + 2));\r
if (str_equiv(argv[1], _T("status"))) exit(control_service(SERVICE_CONTROL_INTERROGATE, argc - 2, argv + 2));\r
+ if (str_equiv(argv[1], _T("rotate"))) exit(control_service(NSSM_SERVICE_CONTROL_ROTATE, argc - 2, argv + 2));\r
if (str_equiv(argv[1], _T("install"))) {\r
if (! is_admin) {\r
print_message(stderr, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_INSTALL);\r
if (str_equiv(argv[1], _T("install"))) {\r
if (! is_admin) {\r
print_message(stderr, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_INSTALL);\r
/* How many milliseconds to wait before updating service status. */\r
#define NSSM_SERVICE_STATUS_DEADLINE 20000\r
\r
/* How many milliseconds to wait before updating service status. */\r
#define NSSM_SERVICE_STATUS_DEADLINE 20000\r
\r
+/* User-defined service controls can be in the range 128-255. */\r
+#define NSSM_SERVICE_CONTROL_ROTATE 128\r
+\r
case SERVICE_CONTROL_PAUSE: return _T("PAUSE");\r
case SERVICE_CONTROL_CONTINUE: return _T("CONTINUE");\r
case SERVICE_CONTROL_INTERROGATE: return _T("INTERROGATE");\r
case SERVICE_CONTROL_PAUSE: return _T("PAUSE");\r
case SERVICE_CONTROL_CONTINUE: return _T("CONTINUE");\r
case SERVICE_CONTROL_INTERROGATE: return _T("INTERROGATE");\r
+ case NSSM_SERVICE_CONTROL_ROTATE: return _T("ROTATE");\r
default: return 0;\r
}\r
}\r
default: return 0;\r
}\r
}\r
*/\r
log_service_control(service->name, control, false);\r
return ERROR_CALL_NOT_IMPLEMENTED;\r
*/\r
log_service_control(service->name, control, false);\r
return ERROR_CALL_NOT_IMPLEMENTED;\r
+\r
+ case NSSM_SERVICE_CONTROL_ROTATE:\r
+ log_service_control(service->name, control, true);\r
+ if (service->rotate_stdout_online) service->rotate_stdout_online = NSSM_ROTATE_ONLINE_ASAP;\r
+ if (service->rotate_stdout_online) service->rotate_stderr_online = NSSM_ROTATE_ONLINE_ASAP;\r
+ return NO_ERROR;\r
}\r
\r
/* Unknown control */\r
}\r
\r
/* Unknown control */\r
#define NSSM_SHARE_INTERACTIVE_PROCESS NSSM_WIN32_SHARE_PROCESS _T("|") NSSM_INTERACTIVE_PROCESS\r
#define NSSM_UNKNOWN _T("?")\r
\r
#define NSSM_SHARE_INTERACTIVE_PROCESS NSSM_WIN32_SHARE_PROCESS _T("|") NSSM_INTERACTIVE_PROCESS\r
#define NSSM_UNKNOWN _T("?")\r
\r
+#define NSSM_ROTATE_OFFLINE 0\r
+#define NSSM_ROTATE_ONLINE 1\r
+#define NSSM_ROTATE_ONLINE_ASAP 2\r
+\r
typedef struct {\r
bool native;\r
TCHAR name[SERVICE_NAME_LENGTH];\r
typedef struct {\r
bool native;\r
TCHAR name[SERVICE_NAME_LENGTH];\r
HANDLE stderr_thread;\r
unsigned long stderr_tid;\r
bool rotate_files;\r
HANDLE stderr_thread;\r
unsigned long stderr_tid;\r
bool rotate_files;\r
- bool rotate_stdout_online;\r
- bool rotate_stderr_online;\r
+ unsigned long rotate_stdout_online;\r
+ unsigned long rotate_stderr_online;\r
unsigned long rotate_seconds;\r
unsigned long rotate_bytes_low;\r
unsigned long rotate_bytes_high;\r
unsigned long rotate_seconds;\r
unsigned long rotate_bytes_low;\r
unsigned long rotate_bytes_high;\r