Browse Source

Enable on-demand rotation.

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.
Iain Patterson 10 years ago
parent
commit
2cd1c7c29e
9 changed files with 38 additions and 9 deletions
  1. 11 1
      README.txt
  2. 1 1
      gui.cpp
  3. 8 5
      io.cpp
  4. 1 0
      io.h
  5. BIN
      messages.mc
  6. 1 0
      nssm.cpp
  7. 3 0
      nssm.h
  8. 7 0
      service.cpp
  9. 6 2
      service.h

+ 11 - 1
README.txt

@@ -315,7 +315,17 @@ They will be rotated regardless of whether NSSM would otherwise have appended
 or replaced them.
 
 NSSM can also rotate files which hit the configured size threshold while the
-service is running.  To enable this feature, set AppRotateOnline to a non-zero
+service is running.  Additionally, you can trigger an on-demand rotation by
+running the command
+
+    nssm rotate <servicename>
+
+On-demand rotations will happen after the next line of data is read from
+the managed application, regardless of the value of AppRotateBytes. Be aware
+that if the application is not particularly verbose the rotation may not
+happen for some time.
+
+To enable online and on-demand rotation, set AppRotateOnline to a non-zero
 value.
 
 Note that online rotation requires NSSM to intercept the application's I/O

+ 1 - 1
gui.cpp

@@ -508,7 +508,7 @@ int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service
   /* Get rotation stuff. */
   if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {
     service->rotate_files = true;
-    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);
     check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, &service->rotate_bytes_low);
   }

+ 8 - 5
io.cpp

@@ -242,7 +242,7 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
 
     /* Try online rotation only if a size threshold is set. */
     logger_t *stdout_logger = 0;
-    if (service->rotate_files && service->rotate_stdout_online && size.QuadPart) {
+    if (service->rotate_files && service->rotate_stdout_online) {
       stdout_logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));
       if (stdout_logger) {
         /* Pipe between application's stdout and our logging handle. */
@@ -256,6 +256,7 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
           stdout_logger->write_handle = stdout_handle;
           stdout_logger->size = (__int64) size.QuadPart;
           stdout_logger->tid_ptr = &service->stdout_tid;
+          stdout_logger->rotate_online = &service->rotate_stdout_online;
 
           /* Logging thread. */
           service->stdout_thread = create_logging_thread(stdout_logger);
@@ -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);
         return 4;
       }
-      service->rotate_stdout_online = false;
+      service->rotate_stdout_online = NSSM_ROTATE_OFFLINE;
     }
 
     set_flags = true;
@@ -321,7 +322,7 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
 
       /* Try online rotation only if a size threshold is set. */
       logger_t *stderr_logger = 0;
-      if (service->rotate_files && service->rotate_stderr_online && size.QuadPart) {
+      if (service->rotate_files && service->rotate_stderr_online) {
         stderr_logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));
         if (stderr_logger) {
           /* Pipe between application's stderr and our logging handle. */
@@ -335,6 +336,7 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
             stderr_logger->write_handle = stderr_handle;
             stderr_logger->size = (__int64) size.QuadPart;
             stderr_logger->tid_ptr = &service->stderr_tid;
+            stderr_logger->rotate_online = &service->rotate_stderr_online;
 
             /* Logging thread. */
             service->stderr_thread = create_logging_thread(stderr_logger);
@@ -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);
           return 7;
         }
-        service->rotate_stderr_online = false;
+        service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
       }
     }
 
@@ -510,7 +512,7 @@ unsigned long WINAPI log_and_rotate(void *arg) {
     }
     else if (ret) continue;
 
-    if (size + (__int64) in >= logger->size) {
+    if (*logger->rotate_online == NSSM_ROTATE_ONLINE_ASAP || (logger->size && size + (__int64) in >= logger->size)) {
       /* Look for newline. */
       unsigned long i;
       for (i = 0; i < in; i++) {
@@ -527,6 +529,7 @@ unsigned long WINAPI log_and_rotate(void *arg) {
           size += (__int64) out;
 
           /* Rotate. */
+          *logger->rotate_online = NSSM_ROTATE_ONLINE;
           TCHAR rotated[MAX_PATH];
           rotated_filename(logger->path, rotated, _countof(rotated), 0);
 

+ 1 - 0
io.h

@@ -21,6 +21,7 @@ typedef struct {
   HANDLE write_handle;
   __int64 size;
   unsigned long *tid_ptr;
+  unsigned long *rotate_online;
 } logger_t;
 
 int get_createfile_parameters(HKEY, TCHAR *, TCHAR *, unsigned long *, unsigned long, unsigned long *, unsigned long, unsigned long *, unsigned long);

BIN
messages.mc


+ 1 - 0
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));
     if (str_equiv(argv[1], _T("continue"))) exit(control_service(SERVICE_CONTROL_CONTINUE, argc - 2, argv + 2));
     if (str_equiv(argv[1], _T("status"))) exit(control_service(SERVICE_CONTROL_INTERROGATE, argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("rotate"))) exit(control_service(NSSM_SERVICE_CONTROL_ROTATE, argc - 2, argv + 2));
     if (str_equiv(argv[1], _T("install"))) {
       if (! is_admin) {
         print_message(stderr, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_INSTALL);

+ 3 - 0
nssm.h

@@ -95,4 +95,7 @@ int usage(int);
 /* How many milliseconds to wait before updating service status. */
 #define NSSM_SERVICE_STATUS_DEADLINE 20000
 
+/* User-defined service controls can be in the range 128-255. */
+#define NSSM_SERVICE_CONTROL_ROTATE 128
+
 #endif

+ 7 - 0
service.cpp

@@ -1281,6 +1281,7 @@ TCHAR *service_control_text(unsigned long control) {
     case SERVICE_CONTROL_PAUSE: return _T("PAUSE");
     case SERVICE_CONTROL_CONTINUE: return _T("CONTINUE");
     case SERVICE_CONTROL_INTERROGATE: return _T("INTERROGATE");
+    case NSSM_SERVICE_CONTROL_ROTATE: return _T("ROTATE");
     default: return 0;
   }
 }
@@ -1368,6 +1369,12 @@ unsigned long WINAPI service_control_handler(unsigned long control, unsigned lon
       */
       log_service_control(service->name, control, false);
       return ERROR_CALL_NOT_IMPLEMENTED;
+
+    case NSSM_SERVICE_CONTROL_ROTATE:
+      log_service_control(service->name, control, true);
+      if (service->rotate_stdout_online) service->rotate_stdout_online = NSSM_ROTATE_ONLINE_ASAP;
+      if (service->rotate_stdout_online) service->rotate_stderr_online = NSSM_ROTATE_ONLINE_ASAP;
+      return NO_ERROR;
   }
 
   /* Unknown control */

+ 6 - 2
service.h

@@ -28,6 +28,10 @@
 #define NSSM_SHARE_INTERACTIVE_PROCESS NSSM_WIN32_SHARE_PROCESS _T("|") NSSM_INTERACTIVE_PROCESS
 #define NSSM_UNKNOWN _T("?")
 
+#define NSSM_ROTATE_OFFLINE 0
+#define NSSM_ROTATE_ONLINE 1
+#define NSSM_ROTATE_ONLINE_ASAP 2
+
 typedef struct {
   bool native;
   TCHAR name[SERVICE_NAME_LENGTH];
@@ -68,8 +72,8 @@ typedef struct {
   HANDLE stderr_thread;
   unsigned long stderr_tid;
   bool rotate_files;
-  bool rotate_stdout_online;
-  bool rotate_stderr_online;
+  unsigned long rotate_stdout_online;
+  unsigned long rotate_stderr_online;
   unsigned long rotate_seconds;
   unsigned long rotate_bytes_low;
   unsigned long rotate_bytes_high;