XRootD
XrdSysLogger.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S y s L o g g e r . c c */
4 /* */
5 /*(c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /*Produced by Andrew Hanushevsky for Stanford University under contract */
7 /* DE-AC02-76-SFO0515 with the Deprtment of Energy */
8 /* */
9 /* This file is part of the XRootD software suite. */
10 /* */
11 /* XRootD is free software: you can redistribute it and/or modify it under */
12 /* the terms of the GNU Lesser General Public License as published by the */
13 /* Free Software Foundation, either version 3 of the License, or (at your */
14 /* option) any later version. */
15 /* */
16 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19 /* License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24 /* */
25 /* The copyright holder's institutional names and contributor's names may not */
26 /* be used to endorse or promote products derived from this software without */
27 /* specific prior written permission of the institution or contributor. */
28 /******************************************************************************/
29 
30 #include <fcntl.h>
31 #include <signal.h>
32 #include <cstdlib>
33 #include <cstdio>
34 #include <cstring>
35 #include <ctime>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #ifndef WIN32
39 #include <dirent.h>
40 #include <unistd.h>
41 #include <strings.h>
42 #include <sys/param.h>
43 #include <termios.h>
44 #include <sys/uio.h>
45 #endif // WIN32
46 
47 #include "XrdOuc/XrdOucTList.hh"
48 
49 #include "XrdSys/XrdSysE2T.hh"
50 #include "XrdSys/XrdSysFD.hh"
51 #include "XrdSys/XrdSysLogger.hh"
52 #include "XrdSys/XrdSysLogging.hh"
53 #include "XrdSys/XrdSysHeaders.hh"
54 #include "XrdSys/XrdSysPlatform.hh"
55 #include "XrdSys/XrdSysPthread.hh"
56 #include "XrdSys/XrdSysTimer.hh"
57 #include "XrdSys/XrdSysUtils.hh"
58 
59 /******************************************************************************/
60 /* G l o b a l s */
61 /******************************************************************************/
62 
63 namespace
64 {
65 XrdOucTListFIFO *tFifo = 0;
66 
67 void Snatch(struct iovec *iov, int iovnum) // Called with logger mutex locked!
68 {
69  XrdOucTList *tlP;
70  char *tBuff, *tbP;
71  int tLen = 0;
72 
73 // Do not save the new line character at the end
74 //
75  if (iovnum && *((char *)iov[iovnum-1].iov_base) == '\n') iovnum--;
76 
77 // Calculate full length
78 //
79  for (int i = 0; i <iovnum; i++) tLen += iov[i].iov_len;
80 
81 // Allocate storage
82 //
83  if (!(tBuff = (char *)malloc(tLen+1))) return;
84 
85 // Copy in the segments into the buffer
86 //
87  tbP = tBuff;
88  for (int i = 0; i <iovnum; i++)
89  {strncpy(tbP, (char *)iov[i].iov_base, iov[i].iov_len);
90  tbP += iov[i].iov_len;
91  }
92  *tbP = 0;
93 
94 // Allocate a new tlist object and add it toi the fifo
95 //
96  tlP = new XrdOucTList;
97  tlP->text = tBuff;
98  tFifo->Add(tlP);
99 }
100 }
101 
102 /******************************************************************************/
103 /* L o c a l D e f i n e s */
104 /******************************************************************************/
105 
106 #define BLAB(x) std::cerr <<"Logger " <<x <<"!!!" <<std::endl
107 
108 bool XrdSysLogger::doForward = false;
109 
110 /******************************************************************************/
111 /* E x t e r n a l T h r e a d I n t e r f a c e s */
112 /******************************************************************************/
113 
114 void *XrdSysLoggerMN(void *carg)
115  {XrdSysLogger::Task *tP = (XrdSysLogger::Task *)carg;
116  while(tP) {tP->Ring(); tP = tP->Next();}
117  return (void *)0;
118  }
119 
123 
125  {}
127  };
128 
129 void *XrdSysLoggerRT(void *carg)
130  {XrdSysLoggerRP *rP = (XrdSysLoggerRP *)carg;
131  XrdSysLogger *lp = rP->logger;
132  rP->active.Post();
133  lp->zHandler();
134  return (void *)0;
135  }
136 
137 /******************************************************************************/
138 /* C o n s t r u c t o r */
139 /******************************************************************************/
140 
141 XrdSysLogger::XrdSysLogger(int ErrFD, int dorotate)
142 {
143  char * logFN;
144 
145  ePath = 0;
146  eInt = 0;
147  eFD = ErrFD;
148  eKeep = 0;
149  doLFR = (dorotate != 0);
150  msgList = 0;
151  taskQ = 0;
152  lfhTID = 0;
153  hiRes = false;
154  fifoFN = 0;
155  reserved1 = 0;
156 
157 // Establish default log file name
158 //
159  if (!(logFN = getenv("XrdSysLOGFILE"))) logFN = getenv("XrdOucLOGFILE");
160 
161 // Establish message routing
162 //
163  if (ErrFD != STDERR_FILENO) baseFD = ErrFD;
164  else {baseFD = XrdSysFD_Dup(ErrFD);
165  Bind(logFN, 1);
166  }
167 }
168 
169 /******************************************************************************/
170 /* A d d M s g */
171 /******************************************************************************/
172 
173 void XrdSysLogger::AddMsg(const char *msg)
174 {
175  mmMsg *tP, *nP = new mmMsg;
176 
177 // Fill out new message
178 //
179  nP->next = 0;
180  nP->msg = strdup(msg);
181  nP->mlen = strlen(msg);
182 
183 // Add new line character if one is missing (we steal the null byte for this)
184 //
185  if (nP->mlen > 1 && nP->msg[nP->mlen-1] != '\n')
186  {nP->msg[nP->mlen] = '\n'; nP->mlen += 1;}
187 
188 // Add this message to the end of the list
189 //
190  Logger_Mutex.Lock();
191  if (!(tP = msgList)) msgList = nP;
192  else {while(tP->next) tP = tP->next;
193  tP->next = nP;
194  }
195  Logger_Mutex.UnLock();
196 }
197 
198 /******************************************************************************/
199 /* A t M i d n i g h t */
200 /******************************************************************************/
201 
203 {
204 
205 // Place this task on the task queue
206 //
207  Logger_Mutex.Lock();
208  mnTask->next = taskQ;
209  taskQ = mnTask;
210  Logger_Mutex.UnLock();
211 }
212 
213 /******************************************************************************/
214 /* B i n d */
215 /******************************************************************************/
216 
217 int XrdSysLogger::Bind(const char *path, int lfh)
218 {
219  XrdSysLoggerRP rtParms(this);
220  int rc;
221 
222 // Kill logfile handler thread if parameters will be changing
223 //
224  if (lfh > 0) lfh = 1;
225  if (lfhTID && (eInt != lfh || !path))
226  {XrdSysThread::Kill(lfhTID);
227  lfhTID = 0;
228  }
229 
230 // Bind to stderr if no path specified
231 //
232  if (ePath) free(ePath);
233  eInt = 0;
234  ePath = 0;
235  if (fifoFN) free(fifoFN);
236  fifoFN = 0; doLFR = false;
237  if (!path) return 0;
238 
239 // Bind to a log file
240 //
241  eInt = lfh;
242  ePath = strdup(path);
243  doLFR = (lfh > 0);
244  if ((rc = ReBind(0))) return rc;
245 
246 // Lock the logs if XRootD is suppose to handle log rotation itself
247 //
248  rc = HandleLogRotateLock( doLFR );
249  if( rc )
250  return -rc;
251 
252 // Handle specifics of lofile rotation
253 //
254  if (eInt == onFifo) {if ((rc = FifoMake())) return -rc;}
255  else if (eInt < 0 && !XrdSysUtils::SigBlock(-eInt))
256  {rc = errno;
257  BLAB("Unable to block logfile signal " <<-eInt <<"; "
258  <<XrdSysE2T(rc));
259  eInt = 0;
260  return -rc;
261  }
262 
263 // Start a log rotation thread
264 //
265  rc = XrdSysThread::Run(&lfhTID, XrdSysLoggerRT, (void *)&rtParms, 0,
266  "Logfile handler");
267  if (!rc) rtParms.active.Wait();
268  return (rc > 0 ? -rc : rc);
269 }
270 
271 /******************************************************************************/
272 /* C a p t u r e */
273 /******************************************************************************/
274 
276 {
277 
278 // Obtain the serailization mutex
279 //
280  Logger_Mutex.Lock();
281 
282 // Set the base for capturing messages
283 //
284  tFifo = tFIFO;
285 
286 // Release the serailization mutex
287 //
288  Logger_Mutex.UnLock();
289 }
290 
291 /******************************************************************************/
292 /* P a r s e K e e p */
293 /******************************************************************************/
294 
295 int XrdSysLogger::ParseKeep(const char *arg)
296 {
297  char *eP;
298 
299 // First check to see if this is a sig type
300 //
301  eKeep = 0;
302  if (isalpha(*arg))
303  {if (!strcmp(arg, "fifo")) return onFifo;
304  return -XrdSysUtils::GetSigNum(arg);
305  }
306 
307 // Process an actual keep count
308 //
309  eKeep = strtoll(arg, &eP, 10);
310  if (!(*eP) || eKeep < 0) {eKeep = -eKeep; return 1;}
311 
312 // Process an actual keep size
313 //
314  if (*(eP+1)) return 0;
315  if (*eP == 'k' || *eP == 'K') eKeep *= 1024LL;
316  else if (*eP == 'm' || *eP == 'M') eKeep *= 1024LL*1024LL;
317  else if (*eP == 'g' || *eP == 'G') eKeep *= 1024LL*1024LL*1024LL;
318  else if (*eP == 't' || *eP == 'T') eKeep *= 1024LL*1024LL*1024LL*1024LL;
319  else return 0;
320 
321 // All done
322 //
323  return 1;
324 }
325 
326 /******************************************************************************/
327 /* P u t */
328 /******************************************************************************/
329 
330 void XrdSysLogger::Put(int iovcnt, struct iovec *iov)
331 {
332  struct timeval tVal;
333  unsigned long tID = XrdSysThread::Num();
334  int retc;
335  char tbuff[32];
336 
337 // Get current time
338 //
339  gettimeofday(&tVal, 0);
340 
341 // Forward the message if there is a plugin involved here
342 //
343  if (doForward)
344  {bool xEnd;
345  if (iov[0].iov_base) xEnd = XrdSysLogging::Forward(tVal,tID,iov,iovcnt);
346  else xEnd = XrdSysLogging::Forward(tVal, tID, &iov[1], iovcnt-1);
347  if (xEnd) return;
348  }
349 
350 // Prefix message with time if calle wants it so
351 //
352  if (!iov[0].iov_base)
353  {iov[0].iov_base = tbuff;
354  iov[0].iov_len = TimeStamp(tVal, tID, tbuff, sizeof(tbuff), hiRes);
355  }
356 
357 // Obtain the serailization mutex if need be
358 //
359  Logger_Mutex.Lock();
360 
361 // If we are capturing messages, do so now
362 //
363  if (tFifo)
364  {Snatch(iov, iovcnt);
365  Logger_Mutex.UnLock();
366  return;
367  }
368 
369 // In theory, writev may write out a partial list. This rarely happens in
370 // practice and so we ignore that possibility (recovery is pretty tough).
371 //
372  do { retc = writev(eFD, (const struct iovec *)iov, iovcnt);}
373  while (retc < 0 && errno == EINTR);
374 
375 // Release the serailization mutex if need be
376 //
377  Logger_Mutex.UnLock();
378 }
379 
380 /******************************************************************************/
381 /* Private: T i m e */
382 /******************************************************************************/
383 
384 int XrdSysLogger::Time(char *tbuff)
385 {
386  struct timeval tVal;
387  const int minblen = 32;
388  struct tm tNow;
389  int i;
390 
391 // Get the current time
392 //
393  gettimeofday(&tVal, 0);
394 
395 // Format the time in human terms
396 //
397  localtime_r((const time_t *) &tVal.tv_sec, &tNow);
398 
399 // Choose appropriate output
400 //
401  if (hiRes)
402  {i = snprintf(tbuff, minblen, "%02d%02d%02d %02d:%02d:%02d.%06d %03ld ",
403  tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
404  tNow.tm_hour, tNow.tm_min, tNow.tm_sec,
405  static_cast<int>(tVal.tv_usec), XrdSysThread::Num());
406  } else {
407  i = snprintf(tbuff, minblen, "%02d%02d%02d %02d:%02d:%02d %03ld ",
408  tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
409  tNow.tm_hour, tNow.tm_min, tNow.tm_sec,
411  }
412  return (i >= minblen ? minblen-1 : i);
413 }
414 
415 /******************************************************************************/
416 /* Private: T i m e S t a m p */
417 /******************************************************************************/
418 
419 int XrdSysLogger::TimeStamp(struct timeval &tVal, unsigned long tID,
420  char *tbuff, int tbsz, bool hires)
421 {
422  struct tm tNow;
423  int i;
424 
425 // Validate tbuff size
426 //
427  if (tbsz <= 0) return 0;
428 
429 // Format the time in human terms
430 //
431  localtime_r((const time_t *) &tVal.tv_sec, &tNow);
432 
433 // Choose appropriate output
434 //
435  if (hires)
436  {i = snprintf(tbuff, tbsz, "%02d%02d%02d %02d:%02d:%02d.%06d %03ld ",
437  tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
438  tNow.tm_hour, tNow.tm_min, tNow.tm_sec,
439  static_cast<int>(tVal.tv_usec), tID);
440  } else {
441  i = snprintf(tbuff, tbsz, "%02d%02d%02d %02d:%02d:%02d %03ld ",
442  tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
443  tNow.tm_hour, tNow.tm_min, tNow.tm_sec, tID);
444  }
445  return (i >= tbsz ? tbsz-1 : i);
446 }
447 
448 /******************************************************************************/
449 /* P r i v a t e M e t h o d s */
450 /******************************************************************************/
451 /******************************************************************************/
452 /* F i f o M a k e */
453 /******************************************************************************/
454 
455 int XrdSysLogger::FifoMake()
456 {
457  struct stat Stat;
458  char buff[2048], *slash;
459  int n, rc, saveInt = eInt;
460 
461 // Assume failure (just to keep down the code)
462 //
463  eInt = 0;
464 
465 // Construct the fifo name
466 //
467  if (!(slash = rindex(ePath, '/')))
468  {*buff = '.';
469  strcpy(buff+1, ePath);
470  } else {
471  n = slash - ePath + 1;
472  strncpy(buff, ePath, n);
473  buff[n] = '.';
474  strcpy(&buff[n+1], slash+1);
475  }
476 
477 // Check if the fifo exists and is usable or that we can create it
478 //
479  if (!stat(buff, &Stat))
480  { if (!S_ISFIFO(Stat.st_mode))
481  {BLAB("Logfile fifo " <<buff <<" exists but is not a fifo");
482  rc = EEXIST;
483  }
484  else if (access(buff, R_OK))
485  {BLAB("Unable to access " <<buff);
486  rc = EACCES;
487  }
488  else rc = 0;
489  if (rc)
490  {if (unlink(buff))
491  {BLAB("Unable to remove " <<buff <<"; " <<XrdSysE2T(errno));
492  return rc;
493  } else {
494  BLAB(buff <<" has been removed");
495  rc = ENOENT;
496  }
497  }
498  } else {
499  rc = errno;
500  if (rc != ENOENT)
501  {BLAB("Unable to stat " <<buff <<"; " <<XrdSysE2T(rc));
502  return rc;
503  }
504  }
505 
506 // Now try to create the fifo if we actually need to
507 //
508  if (rc == ENOENT)
509  {if (mkfifo(buff, S_IRUSR|S_IWUSR))
510  {rc = errno;
511  BLAB("Unable to create logfile fifo " <<buff <<"; " <<XrdSysE2T(rc));
512  return rc;
513  }
514  }
515 
516 // Save the fifo path restore eInt
517 //
518  fifoFN = strdup(buff);
519  eInt = saveInt;
520  return 0;
521 }
522 
523 /******************************************************************************/
524 /* H a n d l e L o g R o t a t e L o c k */
525 /******************************************************************************/
526 int XrdSysLogger::HandleLogRotateLock( bool dorotate )
527 {
528  if( !ePath ) return 0;
529 
530  char *end = rindex(ePath, '/');
531  const std::string lckPath = (end ? std::string(ePath,end+1)+".lock" : ".lock");
532  int rc = unlink( lckPath.c_str() );
533  if( rc && errno != ENOENT )
534  {
535  BLAB( "The logfile lock (" << lckPath.c_str() << ") exists and cannot be removed: " << XrdSysE2T( errno ) );
536  return EEXIST;
537  }
538 
539  if( dorotate )
540  {
541  rc = open( lckPath.c_str(), O_CREAT, 0644 );
542  if( rc < 0 )
543  {
544  BLAB( "Failed to create the logfile lock (" << lckPath.c_str() << "): " << XrdSysE2T( errno ) );
545  return errno;
546  }
547  close( rc );
548  }
549 
550  return 0;
551 }
552 
553 /******************************************************************************/
554 /* R m L o g R o t a t e L o c k */
555 /******************************************************************************/
556 void XrdSysLogger::RmLogRotateLock()
557 {
558  if( !ePath ) return;
559 
560  char *end = rindex(ePath, '/') + 1;
561  const std::string lckPath = std::string( ePath, end ) + ".lock";
562  unlink( lckPath.c_str() );
563 }
564 
565 /******************************************************************************/
566 /* F i f o W a i t */
567 /******************************************************************************/
568 
569 void XrdSysLogger::FifoWait()
570 {
571  char buff[64];
572  int pipeFD, rc;
573 
574 // Open the fifo. We can't have this block as we need to make sure it is
575 // closed on EXEC as fast as possible (Linux has a non-portable solution).
576 //
577  if ((pipeFD = XrdSysFD_Open(fifoFN, O_RDONLY)) < 0)
578  {rc = errno;
579  BLAB("Unable to open logfile fifo " <<fifoFN <<"; " <<XrdSysE2T(rc));
580  eInt = 0;
581  free(fifoFN); fifoFN = 0;
582  return;
583  }
584 
585 // Wait for read, this will block. If we got an EOF then something went wrong!
586 //
587  if (!read(pipeFD, buff, sizeof(buff)))
588  {BLAB("Unexpected EOF on logfile fifo " <<fifoFN);
589  eInt = 0;
590  }
591  close(pipeFD);
592 }
593 
594 /******************************************************************************/
595 /* p u t E m s g */
596 /******************************************************************************/
597 
598 // This internal logging method is used when the caller already has the mutex!
599 
600 void XrdSysLogger::putEmsg(char *msg, int msz)
601 {
602  unsigned long tID = XrdSysThread::Num();
603  char tbuff[32];
604  struct timeval tVal;
605  struct iovec eVec[2] = {{tbuff, 0}, {msg, (size_t)msz}};
606  int retc;
607 
608 // Get current time
609 //
610  gettimeofday(&tVal, 0);
611 
612 // Forward the message if there is a plugin involved here
613 //
614  if (doForward && XrdSysLogging::Forward(tVal, tID, &eVec[1], 1)) return;
615 
616 // Prefix message with time
617 //
618  eVec[0].iov_len = TimeStamp(tVal, tID, tbuff, sizeof(tbuff), hiRes);
619 
620 // In theory, writev may write out a partial list. This rarely happens in
621 // practice and so we ignore that possibility (recovery is pretty tough).
622 //
623  do { retc = writev(eFD, (const struct iovec *)eVec, 2);}
624  while (retc < 0 && errno == EINTR);
625 }
626 
627 /******************************************************************************/
628 /* R e B i n d */
629 /******************************************************************************/
630 
631 int XrdSysLogger::ReBind(int dorename)
632 {
633  const char seq[] = "0123456789";
634  unsigned int i;
635  int newfd;
636  struct tm nowtime;
637  char *bp, buff[MAXPATHLEN+MAXNAMELEN];
638  struct stat bf;
639 
640 // Rename the file to be of the form yyyymmdd corresponding to the date it was
641 // opened. We will add a sequence number (.x) if a conflict occurs.
642 //
643  if (dorename && doLFR)
644  {strcpy(buff, ePath);
645  bp = buff+strlen(ePath);
646  *bp++ = '.';
647  strncpy(bp, Filesfx, 8);
648  bp += 8;
649  *bp = '\0'; *(bp+2) = '\0';
650  for (i = 0; i < sizeof(seq) && !stat(buff, &bf); i++)
651  {*bp = '.'; *(bp+1) = (char)seq[i];}
652  if (i < sizeof(seq)) rename(ePath, buff);
653  }
654 
655 // Compute the suffix for the file
656 //
657  if (doLFR)
658  {time_t eNow = time(0);
659  localtime_r((const time_t *) &eNow, &nowtime);
660  sprintf(buff, "%4d%02d%02d", nowtime.tm_year+1900, nowtime.tm_mon+1,
661  nowtime.tm_mday);
662  memcpy(Filesfx, buff, 8);
663  }
664 
665 // Open the file for output. Note that we can still leak a file descriptor
666 // if a thread forks a process before we are able to do the fcntl(), sigh.
667 //
668  if ((newfd = XrdSysFD_Open(ePath,O_WRONLY|O_APPEND|O_CREAT,0644)) < 0)
669  return -errno;
670 
671 // Now set the file descriptor to be the same as the error FD. This will
672 // close the previously opened file, if any.
673 //
674  if (dup2(newfd, eFD) < 0)
675  {int rc = errno;
676  close(newfd);
677  return -rc;
678  }
679  close(newfd);
680 
681 // Check if we should trim log files
682 //
683  if (eKeep && doLFR) Trim();
684  return 0;
685 }
686 
687 /******************************************************************************/
688 /* T r i m */
689 /******************************************************************************/
690 
691 #ifndef WIN32
692 void XrdSysLogger::Trim()
693 {
694  struct LogFile
695  {LogFile *next;
696  char *fn;
697  off_t sz;
698  time_t tm;
699 
700  LogFile(char *xfn, off_t xsz, time_t xtm)
701  {fn = (xfn ? strdup(xfn) : 0); sz = xsz; tm = xtm; next = 0;}
702  ~LogFile()
703  {if (fn) free(fn);
704  if (next) delete next;
705  }
706  } logList(0,0,0);
707 
708  struct LogFile *logEnt, *logPrev, *logNow;
709  char eBuff[2048], logFN[MAXNAMELEN+8], logDir[MAXPATHLEN+8], *logSfx;
710  struct dirent *dp;
711  struct stat buff;
712  long long totSz = 0;
713  int n,rc, totNum= 0;
714  DIR *DFD;
715 
716 // Ignore this call if we are not deleting log files
717 //
718  if (!eKeep) return;
719 
720 // Construct the directory path
721 //
722  if (!ePath) return;
723  strcpy(logDir, ePath);
724  if (!(logSfx = rindex(logDir, '/'))) return;
725  *logSfx = '\0';
726  strcpy(logFN, logSfx+1);
727  n = strlen(logFN);
728 
729 // Open the directory
730 //
731  if (!(DFD = opendir(logDir)))
732  {int msz = snprintf(eBuff, 2048, "Error %d (%s) opening log directory %s\n",
733  errno, XrdSysE2T(errno), logDir);
734  putEmsg(eBuff, msz);
735  return;
736  }
737  *logSfx++ = '/';
738 
739 // Record all of the log files currently in this directory
740 //
741  errno = 0;
742  while((dp = readdir(DFD)))
743  {if (strncmp(dp->d_name, logFN, n)) continue;
744  strcpy(logSfx, dp->d_name);
745  if (stat(logDir, &buff) || !(buff.st_mode & S_IFREG)) continue;
746 
747  totNum++; totSz += buff.st_size;
748  logEnt = new LogFile(dp->d_name, buff.st_size, buff.st_mtime);
749  logPrev = &logList; logNow = logList.next;
750  while(logNow && logNow->tm < buff.st_mtime)
751  {logPrev = logNow; logNow = logNow->next;}
752 
753  logPrev->next = logEnt;
754  logEnt->next = logNow;
755  }
756 
757 // Check if we received an error
758 //
759  rc = errno; closedir(DFD);
760  if (rc)
761  {int msz = snprintf(eBuff, 2048, "Error %d (%s) reading log directory %s\n",
762  rc, XrdSysE2T(rc), logDir);
763  putEmsg(eBuff, msz);
764  return;
765  }
766 
767 // If there is only one log file here no need to
768 //
769  if (totNum <= 1) return;
770 
771 // Check if we need to trim log files
772 //
773  if (eKeep < 0)
774  {if ((totNum += eKeep) <= 0) return;
775  } else {
776  if (totSz <= eKeep) return;
777  logNow = logList.next; totNum = 0;
778  while(logNow && totSz > eKeep)
779  {totNum++; totSz -= logNow->sz; logNow = logNow->next;}
780  }
781 
782 // Now start deleting log files
783 //
784  logNow = logList.next;
785  while(logNow && totNum--)
786  {strcpy(logSfx, logNow->fn);
787  if (unlink(logDir))
788  rc = snprintf(eBuff, 2048, "Error %d (%s) removing log file %s\n",
789  errno, XrdSysE2T(errno), logDir);
790  else rc = snprintf(eBuff, 2048, "Removed log file %s\n", logDir);
791  putEmsg(eBuff, rc);
792  logNow = logNow->next;
793  }
794 }
795 #else
796 void XrdSysLogger::Trim()
797 {
798 }
799 #endif
800 
801 /******************************************************************************/
802 /* z H a n d l e r */
803 /******************************************************************************/
804 #include <poll.h>
805 
807 {
808  mmMsg *mP;
809  sigset_t sigset;
810  pthread_t tid;
811  int signo, rc;
812  Task *tP;
813 
814 // If we will be handling via signals, set it up now
815 //
816  if (eInt < 0 && !fifoFN)
817  {signo = -eInt;
818  if ((sigemptyset(&sigset) == -1)
819  || (sigaddset(&sigset,signo) == -1))
820  {rc = errno;
821  BLAB("Unable to use logfile signal " <<signo <<"; " <<XrdSysE2T(rc));
822  eInt = 0;
823  }
824  }
825 
826 // This is a perpetual loop to handle the log file
827 //
828  while(1)
829  { if (fifoFN) FifoWait();
830  else if (eInt >= 0) XrdSysTimer::Wait4Midnight();
831  else if ((sigwait(&sigset, &signo) == -1))
832  {rc = errno;
833  BLAB("Unable to wait on logfile signal " <<signo
834  <<"; " <<XrdSysE2T(rc));
835  eInt = 0;
836  continue;
837  }
838 
839  Logger_Mutex.Lock();
840  ReBind();
841 
842  mP = msgList;
843  while(mP)
844  {putEmsg(mP->msg, mP->mlen);
845  mP = mP->next;
846  }
847  tP = taskQ;
848  Logger_Mutex.UnLock();
849 
850  if (tP)
851  {if (XrdSysThread::Run(&tid, XrdSysLoggerMN, (void *)tP, 0,
852  "Midnight Ringer Task"))
853  {char eBuff[256];
854  rc = sprintf(eBuff, "Error %d (%s) running ringer task.\n",
855  errno, XrdSysE2T(errno));
856  putEmsg(eBuff, rc);
857  }
858  }
859  }
860 }
struct stat Stat
Definition: XrdCks.cc:49
int stat(const char *path, struct stat *buf)
struct dirent * readdir(DIR *dirp)
int open(const char *path, int oflag,...)
int unlink(const char *path)
int rename(const char *oldpath, const char *newpath)
int access(const char *path, int amode)
int closedir(DIR *dirp)
ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
ssize_t read(int fildes, void *buf, size_t nbyte)
DIR * opendir(const char *path)
#define close(a)
Definition: XrdPosix.hh:43
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
#define BLAB(x)
void * XrdSysLoggerRT(void *carg)
void * XrdSysLoggerMN(void *carg)
void Add(XrdOucTList *tP)
Definition: XrdOucTList.hh:105
char * text
Definition: XrdOucTList.hh:46
virtual void Ring()=0
This method gets called at midnight.
static const int onFifo
void Put(int iovcnt, struct iovec *iov)
void AddMsg(const char *msg)
XrdSysLogger(int ErrFD=STDERR_FILENO, int xrotate=1)
void AtMidnight(Task *mnTask)
void Capture(XrdOucTListFIFO *tFIFO)
int Bind(const char *path, int lfh=0)
int ParseKeep(const char *arg)
static bool Forward(struct timeval mtime, unsigned long tID, struct iovec *iov, int iovcnt)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
static int Kill(pthread_t tid)
static unsigned long Num(void)
static void Wait4Midnight()
Definition: XrdSysTimer.cc:252
static bool SigBlock()
Definition: XrdSysUtils.cc:188
static int GetSigNum(const char *sname)
Definition: XrdSysUtils.cc:165
XrdSysLoggerRP(XrdSysLogger *lp)
XrdSysLogger * logger
XrdSysSemaphore active