Enable on-demand rotation.
authorIain Patterson <me@iain.cx>
Sun, 12 Jan 2014 23:56:10 +0000 (23:56 +0000)
committerIain Patterson <me@iain.cx>
Sun, 12 Jan 2014 23:56:10 +0000 (23:56 +0000)
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.

README.txt
gui.cpp
io.cpp
io.h
messages.mc
nssm.cpp
nssm.h
service.cpp
service.h

index 3769d4c..0affeb3 100644 (file)
@@ -315,7 +315,17 @@ They will be rotated regardless of whether NSSM would otherwise have appended
 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
diff --git a/gui.cpp b/gui.cpp
index c09b363..64382f4 100644 (file)
--- a/gui.cpp
+++ b/gui.cpp
@@ -508,7 +508,7 @@ int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service
   /* 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
diff --git a/io.cpp b/io.cpp
index 2602dc2..79848e9 100644 (file)
--- a/io.cpp
+++ b/io.cpp
@@ -242,7 +242,7 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
 \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
@@ -256,6 +256,7 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
           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
@@ -283,7 +284,7 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
         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
@@ -321,7 +322,7 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
 \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
@@ -335,6 +336,7 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
             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
@@ -362,7 +364,7 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
           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
     }\r
 \r
       }\r
     }\r
 \r
@@ -510,7 +512,7 @@ unsigned long WINAPI log_and_rotate(void *arg) {
     }\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
@@ -527,6 +529,7 @@ unsigned long WINAPI log_and_rotate(void *arg) {
           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
diff --git a/io.h b/io.h
index 23c8488..60c3fd5 100644 (file)
--- a/io.h
+++ b/io.h
@@ -21,6 +21,7 @@ typedef struct {
   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
index 68b5289..d8f6f0e 100644 (file)
Binary files a/messages.mc and b/messages.mc differ
index 8dd264a..498a213 100644 (file)
--- a/nssm.cpp
+++ b/nssm.cpp
@@ -108,6 +108,7 @@ int _tmain(int argc, TCHAR **argv) {
     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
diff --git a/nssm.h b/nssm.h
index f6c3f35..79c2065 100644 (file)
--- a/nssm.h
+++ b/nssm.h
@@ -95,4 +95,7 @@ int usage(int);
 /* 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
 #endif\r
 #endif\r
index d0141a1..b8c73ef 100644 (file)
@@ -1281,6 +1281,7 @@ TCHAR *service_control_text(unsigned long control) {
     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
@@ -1368,6 +1369,12 @@ unsigned long WINAPI service_control_handler(unsigned long control, unsigned lon
       */\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
index 8549fee..45680cf 100644 (file)
--- a/service.h
+++ b/service.h
 #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
@@ -68,8 +72,8 @@ typedef struct {
   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