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
-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
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
-    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
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
-    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
@@ -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->rotate_online = &service->rotate_stdout_online;\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
-      service->rotate_stdout_online = false;\r
+      service->rotate_stdout_online = NSSM_ROTATE_OFFLINE;\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
-      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
@@ -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->rotate_online = &service->rotate_stderr_online;\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
-        service->rotate_stderr_online = false;\r
+        service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;\r
       }\r
     }\r
 \r
@@ -510,7 +512,7 @@ unsigned long WINAPI log_and_rotate(void *arg) {
     }\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
@@ -527,6 +529,7 @@ unsigned long WINAPI log_and_rotate(void *arg) {
           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
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
+  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
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("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
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
+/* User-defined service controls can be in the range 128-255. */\r
+#define NSSM_SERVICE_CONTROL_ROTATE 128\r
+\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 NSSM_SERVICE_CONTROL_ROTATE: return _T("ROTATE");\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
+    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
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_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
@@ -68,8 +72,8 @@ typedef struct {
   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