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 = ErrFD;
165  if (logFN)
166  {baseFD = XrdSysFD_Dup(ErrFD);
167  Bind(logFN, 1);
168  }
169  }
170 }
171 
172 /******************************************************************************/
173 /* A d d M s g */
174 /******************************************************************************/
175 
176 void XrdSysLogger::AddMsg(const char *msg)
177 {
178  mmMsg *tP, *nP = new mmMsg;
179 
180 // Fill out new message
181 //
182  nP->next = 0;
183  nP->msg = strdup(msg);
184  nP->mlen = strlen(msg);
185 
186 // Add new line character if one is missing (we steal the null byte for this)
187 //
188  if (nP->mlen > 1 && nP->msg[nP->mlen-1] != '\n')
189  {nP->msg[nP->mlen] = '\n'; nP->mlen += 1;}
190 
191 // Add this message to the end of the list
192 //
193  Logger_Mutex.Lock();
194  if (!(tP = msgList)) msgList = nP;
195  else {while(tP->next) tP = tP->next;
196  tP->next = nP;
197  }
198  Logger_Mutex.UnLock();
199 }
200 
201 /******************************************************************************/
202 /* A t M i d n i g h t */
203 /******************************************************************************/
204 
206 {
207 
208 // Place this task on the task queue
209 //
210  Logger_Mutex.Lock();
211  mnTask->next = taskQ;
212  taskQ = mnTask;
213  Logger_Mutex.UnLock();
214 }
215 
216 /******************************************************************************/
217 /* B i n d */
218 /******************************************************************************/
219 
220 int XrdSysLogger::Bind(const char *path, int lfh)
221 {
222  XrdSysLoggerRP rtParms(this);
223  int rc;
224 
225 // Kill logfile handler thread if parameters will be changing
226 //
227  if (lfh > 0) lfh = 1;
228  if (lfhTID && (eInt != lfh || !path))
229  {XrdSysThread::Kill(lfhTID);
230  lfhTID = 0;
231  }
232 
233 // Bind to stderr if no path specified
234 //
235  if (ePath) free(ePath);
236  eInt = 0;
237  ePath = 0;
238  if (fifoFN) free(fifoFN);
239  fifoFN = 0; doLFR = false;
240  if (!path) return 0;
241 
242 // Bind to a log file
243 //
244  eInt = lfh;
245  ePath = strdup(path);
246  doLFR = (lfh > 0);
247  if ((rc = ReBind(0))) return rc;
248 
249 // Lock the logs if XRootD is suppose to handle log rotation itself
250 //
251  rc = HandleLogRotateLock( doLFR );
252  if( rc )
253  return -rc;
254 
255 // Handle specifics of lofile rotation
256 //
257  if (eInt == onFifo) {if ((rc = FifoMake())) return -rc;}
258  else if (eInt < 0 && !XrdSysUtils::SigBlock(-eInt))
259  {rc = errno;
260  BLAB("Unable to block logfile signal " <<-eInt <<"; "
261  <<XrdSysE2T(rc));
262  eInt = 0;
263  return -rc;
264  }
265 
266 // Start a log rotation thread
267 //
268  rc = XrdSysThread::Run(&lfhTID, XrdSysLoggerRT, (void *)&rtParms, 0,
269  "Logfile handler");
270  if (!rc) rtParms.active.Wait();
271  return (rc > 0 ? -rc : rc);
272 }
273 
274 /******************************************************************************/
275 /* C a p t u r e */
276 /******************************************************************************/
277 
279 {
280 
281 // Obtain the serailization mutex
282 //
283  Logger_Mutex.Lock();
284 
285 // Set the base for capturing messages
286 //
287  tFifo = tFIFO;
288 
289 // Release the serailization mutex
290 //
291  Logger_Mutex.UnLock();
292 }
293 
294 /******************************************************************************/
295 /* P a r s e K e e p */
296 /******************************************************************************/
297 
298 int XrdSysLogger::ParseKeep(const char *arg)
299 {
300  char *eP;
301 
302 // First check to see if this is a sig type
303 //
304  eKeep = 0;
305  if (isalpha(*arg))
306  {if (!strcmp(arg, "fifo")) return onFifo;
307  return -XrdSysUtils::GetSigNum(arg);
308  }
309 
310 // Process an actual keep count
311 //
312  eKeep = strtoll(arg, &eP, 10);
313  if (!(*eP) || eKeep < 0) {eKeep = -eKeep; return 1;}
314 
315 // Process an actual keep size
316 //
317  if (*(eP+1)) return 0;
318  if (*eP == 'k' || *eP == 'K') eKeep *= 1024LL;
319  else if (*eP == 'm' || *eP == 'M') eKeep *= 1024LL*1024LL;
320  else if (*eP == 'g' || *eP == 'G') eKeep *= 1024LL*1024LL*1024LL;
321  else if (*eP == 't' || *eP == 'T') eKeep *= 1024LL*1024LL*1024LL*1024LL;
322  else return 0;
323 
324 // All done
325 //
326  return 1;
327 }
328 
329 /******************************************************************************/
330 /* P u t */
331 /******************************************************************************/
332 
333 void XrdSysLogger::Put(int iovcnt, struct iovec *iov)
334 {
335  struct timeval tVal;
336  unsigned long tID = XrdSysThread::Num();
337  int retc;
338  char tbuff[32];
339 
340 // Get current time
341 //
342  gettimeofday(&tVal, 0);
343 
344 // Forward the message if there is a plugin involved here
345 //
346  if (doForward)
347  {bool xEnd;
348  if (iov[0].iov_base) xEnd = XrdSysLogging::Forward(tVal,tID,iov,iovcnt);
349  else xEnd = XrdSysLogging::Forward(tVal, tID, &iov[1], iovcnt-1);
350  if (xEnd) return;
351  }
352 
353 // Prefix message with time if calle wants it so
354 //
355  if (!iov[0].iov_base)
356  {iov[0].iov_base = tbuff;
357  iov[0].iov_len = TimeStamp(tVal, tID, tbuff, sizeof(tbuff), hiRes);
358  }
359 
360 // Obtain the serailization mutex if need be
361 //
362  Logger_Mutex.Lock();
363 
364 // If we are capturing messages, do so now
365 //
366  if (tFifo)
367  {Snatch(iov, iovcnt);
368  Logger_Mutex.UnLock();
369  return;
370  }
371 
372 // In theory, writev may write out a partial list. This rarely happens in
373 // practice and so we ignore that possibility (recovery is pretty tough).
374 //
375  do { retc = writev(eFD, (const struct iovec *)iov, iovcnt);}
376  while (retc < 0 && errno == EINTR);
377 
378 // Release the serailization mutex if need be
379 //
380  Logger_Mutex.UnLock();
381 }
382 
383 /******************************************************************************/
384 /* Private: T i m e */
385 /******************************************************************************/
386 
387 int XrdSysLogger::Time(char *tbuff)
388 {
389  struct timeval tVal;
390  const int minblen = 32;
391  struct tm tNow;
392  int i;
393 
394 // Get the current time
395 //
396  gettimeofday(&tVal, 0);
397 
398 // Format the time in human terms
399 //
400  localtime_r((const time_t *) &tVal.tv_sec, &tNow);
401 
402 // Choose appropriate output
403 //
404  if (hiRes)
405  {i = snprintf(tbuff, minblen, "%02d%02d%02d %02d:%02d:%02d.%06d %03ld ",
406  tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
407  tNow.tm_hour, tNow.tm_min, tNow.tm_sec,
408  static_cast<int>(tVal.tv_usec), XrdSysThread::Num());
409  } else {
410  i = snprintf(tbuff, minblen, "%02d%02d%02d %02d:%02d:%02d %03ld ",
411  tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
412  tNow.tm_hour, tNow.tm_min, tNow.tm_sec,
414  }
415  return (i >= minblen ? minblen-1 : i);
416 }
417 
418 /******************************************************************************/
419 /* Private: T i m e S t a m p */
420 /******************************************************************************/
421 
422 int XrdSysLogger::TimeStamp(struct timeval &tVal, unsigned long tID,
423  char *tbuff, int tbsz, bool hires)
424 {
425  struct tm tNow;
426  int i;
427 
428 // Validate tbuff size
429 //
430  if (tbsz <= 0) return 0;
431 
432 // Format the time in human terms
433 //
434  localtime_r((const time_t *) &tVal.tv_sec, &tNow);
435 
436 // Choose appropriate output
437 //
438  if (hires)
439  {i = snprintf(tbuff, tbsz, "%02d%02d%02d %02d:%02d:%02d.%06d %03ld ",
440  tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
441  tNow.tm_hour, tNow.tm_min, tNow.tm_sec,
442  static_cast<int>(tVal.tv_usec), tID);
443  } else {
444  i = snprintf(tbuff, tbsz, "%02d%02d%02d %02d:%02d:%02d %03ld ",
445  tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
446  tNow.tm_hour, tNow.tm_min, tNow.tm_sec, tID);
447  }
448  return (i >= tbsz ? tbsz-1 : i);
449 }
450 
451 /******************************************************************************/
452 /* P r i v a t e M e t h o d s */
453 /******************************************************************************/
454 /******************************************************************************/
455 /* F i f o M a k e */
456 /******************************************************************************/
457 
458 int XrdSysLogger::FifoMake()
459 {
460  struct stat Stat;
461  char buff[2048], *slash;
462  int n, rc, saveInt = eInt;
463 
464 // Assume failure (just to keep down the code)
465 //
466  eInt = 0;
467 
468 // Construct the fifo name
469 //
470  if (!(slash = rindex(ePath, '/')))
471  {*buff = '.';
472  strcpy(buff+1, ePath);
473  } else {
474  n = slash - ePath + 1;
475  strncpy(buff, ePath, n);
476  buff[n] = '.';
477  strcpy(&buff[n+1], slash+1);
478  }
479 
480 // Check if the fifo exists and is usable or that we can create it
481 //
482  if (!stat(buff, &Stat))
483  { if (!S_ISFIFO(Stat.st_mode))
484  {BLAB("Logfile fifo " <<buff <<" exists but is not a fifo");
485  rc = EEXIST;
486  }
487  else if (access(buff, R_OK))
488  {BLAB("Unable to access " <<buff);
489  rc = EACCES;
490  }
491  else rc = 0;
492  if (rc)
493  {if (unlink(buff))
494  {BLAB("Unable to remove " <<buff <<"; " <<XrdSysE2T(errno));
495  return rc;
496  } else {
497  BLAB(buff <<" has been removed");
498  rc = ENOENT;
499  }
500  }
501  } else {
502  rc = errno;
503  if (rc != ENOENT)
504  {BLAB("Unable to stat " <<buff <<"; " <<XrdSysE2T(rc));
505  return rc;
506  }
507  }
508 
509 // Now try to create the fifo if we actually need to
510 //
511  if (rc == ENOENT)
512  {if (mkfifo(buff, S_IRUSR|S_IWUSR))
513  {rc = errno;
514  BLAB("Unable to create logfile fifo " <<buff <<"; " <<XrdSysE2T(rc));
515  return rc;
516  }
517  }
518 
519 // Save the fifo path restore eInt
520 //
521  fifoFN = strdup(buff);
522  eInt = saveInt;
523  return 0;
524 }
525 
526 /******************************************************************************/
527 /* H a n d l e L o g R o t a t e L o c k */
528 /******************************************************************************/
529 int XrdSysLogger::HandleLogRotateLock( bool dorotate )
530 {
531  if( !ePath ) return 0;
532 
533  char *end = rindex(ePath, '/');
534  const std::string lckPath = (end ? std::string(ePath,end+1)+".lock" : ".lock");
535  int rc = unlink( lckPath.c_str() );
536  if( rc && errno != ENOENT )
537  {
538  BLAB( "The logfile lock (" << lckPath.c_str() << ") exists and cannot be removed: " << XrdSysE2T( errno ) );
539  return EEXIST;
540  }
541 
542  if( dorotate )
543  {
544  rc = open( lckPath.c_str(), O_CREAT, 0644 );
545  if( rc < 0 )
546  {
547  BLAB( "Failed to create the logfile lock (" << lckPath.c_str() << "): " << XrdSysE2T( errno ) );
548  return errno;
549  }
550  close( rc );
551  }
552 
553  return 0;
554 }
555 
556 /******************************************************************************/
557 /* R m L o g R o t a t e L o c k */
558 /******************************************************************************/
559 void XrdSysLogger::RmLogRotateLock()
560 {
561  if( !ePath ) return;
562 
563  char *end = rindex(ePath, '/') + 1;
564  const std::string lckPath = std::string( ePath, end ) + ".lock";
565  unlink( lckPath.c_str() );
566 }
567 
568 /******************************************************************************/
569 /* F i f o W a i t */
570 /******************************************************************************/
571 
572 void XrdSysLogger::FifoWait()
573 {
574  char buff[64];
575  int pipeFD, rc;
576 
577 // Open the fifo. We can't have this block as we need to make sure it is
578 // closed on EXEC as fast as possible (Linux has a non-portable solution).
579 //
580  if ((pipeFD = XrdSysFD_Open(fifoFN, O_RDONLY)) < 0)
581  {rc = errno;
582  BLAB("Unable to open logfile fifo " <<fifoFN <<"; " <<XrdSysE2T(rc));
583  eInt = 0;
584  free(fifoFN); fifoFN = 0;
585  return;
586  }
587 
588 // Wait for read, this will block. If we got an EOF then something went wrong!
589 //
590  if (!read(pipeFD, buff, sizeof(buff)))
591  {BLAB("Unexpected EOF on logfile fifo " <<fifoFN);
592  eInt = 0;
593  }
594  close(pipeFD);
595 }
596 
597 /******************************************************************************/
598 /* p u t E m s g */
599 /******************************************************************************/
600 
601 // This internal logging method is used when the caller already has the mutex!
602 
603 void XrdSysLogger::putEmsg(char *msg, int msz)
604 {
605  unsigned long tID = XrdSysThread::Num();
606  char tbuff[32];
607  struct timeval tVal;
608  struct iovec eVec[2] = {{tbuff, 0}, {msg, (size_t)msz}};
609  int retc;
610 
611 // Get current time
612 //
613  gettimeofday(&tVal, 0);
614 
615 // Forward the message if there is a plugin involved here
616 //
617  if (doForward && XrdSysLogging::Forward(tVal, tID, &eVec[1], 1)) return;
618 
619 // Prefix message with time
620 //
621  eVec[0].iov_len = TimeStamp(tVal, tID, tbuff, sizeof(tbuff), hiRes);
622 
623 // In theory, writev may write out a partial list. This rarely happens in
624 // practice and so we ignore that possibility (recovery is pretty tough).
625 //
626  do { retc = writev(eFD, (const struct iovec *)eVec, 2);}
627  while (retc < 0 && errno == EINTR);
628 }
629 
630 /******************************************************************************/
631 /* R e B i n d */
632 /******************************************************************************/
633 
634 int XrdSysLogger::ReBind(int dorename)
635 {
636  const char seq[] = "0123456789";
637  unsigned int i;
638  int newfd;
639  struct tm nowtime;
640  char *bp, buff[MAXPATHLEN+MAXNAMELEN];
641  struct stat bf;
642 
643 // Rename the file to be of the form yyyymmdd corresponding to the date it was
644 // opened. We will add a sequence number (.x) if a conflict occurs.
645 //
646  if (dorename && doLFR)
647  {strcpy(buff, ePath);
648  bp = buff+strlen(ePath);
649  *bp++ = '.';
650  strncpy(bp, Filesfx, 8);
651  bp += 8;
652  *bp = '\0'; *(bp+2) = '\0';
653  for (i = 0; i < sizeof(seq) && !stat(buff, &bf); i++)
654  {*bp = '.'; *(bp+1) = (char)seq[i];}
655  if (i < sizeof(seq)) rename(ePath, buff);
656  }
657 
658 // Compute the suffix for the file
659 //
660  if (doLFR)
661  {time_t eNow = time(0);
662  localtime_r((const time_t *) &eNow, &nowtime);
663  sprintf(buff, "%4d%02d%02d", nowtime.tm_year+1900, nowtime.tm_mon+1,
664  nowtime.tm_mday);
665  memcpy(Filesfx, buff, 8);
666  }
667 
668 // Open the file for output. Note that we can still leak a file descriptor
669 // if a thread forks a process before we are able to do the fcntl(), sigh.
670 //
671  if ((newfd = XrdSysFD_Open(ePath,O_WRONLY|O_APPEND|O_CREAT,0644)) < 0)
672  return -errno;
673 
674 // Now set the file descriptor to be the same as the error FD. This will
675 // close the previously opened file, if any.
676 //
677  if (dup2(newfd, eFD) < 0)
678  {int rc = errno;
679  close(newfd);
680  return -rc;
681  }
682  close(newfd);
683 
684 // Check if we should trim log files
685 //
686  if (eKeep && doLFR) Trim();
687  return 0;
688 }
689 
690 /******************************************************************************/
691 /* T r i m */
692 /******************************************************************************/
693 
694 #ifndef WIN32
695 void XrdSysLogger::Trim()
696 {
697  struct LogFile
698  {LogFile *next;
699  char *fn;
700  off_t sz;
701  time_t tm;
702 
703  LogFile(char *xfn, off_t xsz, time_t xtm)
704  {fn = (xfn ? strdup(xfn) : 0); sz = xsz; tm = xtm; next = 0;}
705  ~LogFile()
706  {if (fn) free(fn);
707  if (next) delete next;
708  }
709  } logList(0,0,0);
710 
711  struct LogFile *logEnt, *logPrev, *logNow;
712  char eBuff[2048], logFN[MAXNAMELEN+8], logDir[MAXPATHLEN+8], *logSfx;
713  struct dirent *dp;
714  struct stat buff;
715  long long totSz = 0;
716  int n,rc, totNum= 0;
717  DIR *DFD;
718 
719 // Ignore this call if we are not deleting log files
720 //
721  if (!eKeep) return;
722 
723 // Construct the directory path
724 //
725  if (!ePath) return;
726  strcpy(logDir, ePath);
727  if (!(logSfx = rindex(logDir, '/'))) return;
728  *logSfx = '\0';
729  strcpy(logFN, logSfx+1);
730  n = strlen(logFN);
731 
732 // Open the directory
733 //
734  if (!(DFD = opendir(logDir)))
735  {int msz = snprintf(eBuff, 2048, "Error %d (%s) opening log directory %s\n",
736  errno, XrdSysE2T(errno), logDir);
737  putEmsg(eBuff, msz);
738  return;
739  }
740  *logSfx++ = '/';
741 
742 // Record all of the log files currently in this directory
743 //
744  errno = 0;
745  while((dp = readdir(DFD)))
746  {if (strncmp(dp->d_name, logFN, n)) continue;
747  strcpy(logSfx, dp->d_name);
748  if (stat(logDir, &buff) || !(buff.st_mode & S_IFREG)) continue;
749 
750  totNum++; totSz += buff.st_size;
751  logEnt = new LogFile(dp->d_name, buff.st_size, buff.st_mtime);
752  logPrev = &logList; logNow = logList.next;
753  while(logNow && logNow->tm < buff.st_mtime)
754  {logPrev = logNow; logNow = logNow->next;}
755 
756  logPrev->next = logEnt;
757  logEnt->next = logNow;
758  }
759 
760 // Check if we received an error
761 //
762  rc = errno; closedir(DFD);
763  if (rc)
764  {int msz = snprintf(eBuff, 2048, "Error %d (%s) reading log directory %s\n",
765  rc, XrdSysE2T(rc), logDir);
766  putEmsg(eBuff, msz);
767  return;
768  }
769 
770 // If there is only one log file here no need to
771 //
772  if (totNum <= 1) return;
773 
774 // Check if we need to trim log files
775 //
776  if (eKeep < 0)
777  {if ((totNum += eKeep) <= 0) return;
778  } else {
779  if (totSz <= eKeep) return;
780  logNow = logList.next; totNum = 0;
781  while(logNow && totSz > eKeep)
782  {totNum++; totSz -= logNow->sz; logNow = logNow->next;}
783  }
784 
785 // Now start deleting log files
786 //
787  logNow = logList.next;
788  while(logNow && totNum--)
789  {strcpy(logSfx, logNow->fn);
790  if (unlink(logDir))
791  rc = snprintf(eBuff, 2048, "Error %d (%s) removing log file %s\n",
792  errno, XrdSysE2T(errno), logDir);
793  else rc = snprintf(eBuff, 2048, "Removed log file %s\n", logDir);
794  putEmsg(eBuff, rc);
795  logNow = logNow->next;
796  }
797 }
798 #else
799 void XrdSysLogger::Trim()
800 {
801 }
802 #endif
803 
804 /******************************************************************************/
805 /* z H a n d l e r */
806 /******************************************************************************/
807 #include <poll.h>
808 
810 {
811  mmMsg *mP;
812  sigset_t sigset;
813  pthread_t tid;
814  int signo, rc;
815  Task *tP;
816 
817 // If we will be handling via signals, set it up now
818 //
819  if (eInt < 0 && !fifoFN)
820  {signo = -eInt;
821  if ((sigemptyset(&sigset) == -1)
822  || (sigaddset(&sigset,signo) == -1))
823  {rc = errno;
824  BLAB("Unable to use logfile signal " <<signo <<"; " <<XrdSysE2T(rc));
825  eInt = 0;
826  }
827  }
828 
829 // This is a perpetual loop to handle the log file
830 //
831  while(1)
832  { if (fifoFN) FifoWait();
833  else if (eInt >= 0) XrdSysTimer::Wait4Midnight();
834  else if ((sigwait(&sigset, &signo) == -1))
835  {rc = errno;
836  BLAB("Unable to wait on logfile signal " <<signo
837  <<"; " <<XrdSysE2T(rc));
838  eInt = 0;
839  continue;
840  }
841 
842  Logger_Mutex.Lock();
843  ReBind();
844 
845  mP = msgList;
846  while(mP)
847  {putEmsg(mP->msg, mP->mlen);
848  mP = mP->next;
849  }
850  tP = taskQ;
851  Logger_Mutex.UnLock();
852 
853  if (tP)
854  {if (XrdSysThread::Run(&tid, XrdSysLoggerMN, (void *)tP, 0,
855  "Midnight Ringer Task"))
856  {char eBuff[256];
857  rc = sprintf(eBuff, "Error %d (%s) running ringer task.\n",
858  errno, XrdSysE2T(errno));
859  putEmsg(eBuff, rc);
860  }
861  }
862  }
863 }
struct stat Stat
Definition: XrdCks.cc:49
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:48
#define open
Definition: XrdPosix.hh:76
#define stat(a, b)
Definition: XrdPosix.hh:101
#define readdir(a)
Definition: XrdPosix.hh:86
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