XRootD
XrdOucLogging.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d O u c L o g g i n g . c c */
4 /* */
5 /* (c) 2016 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <cerrno>
32 #include <cstdio>
33 #include <cstring>
34 
35 #include "XrdVersion.hh"
36 
37 #include "XrdOuc/XrdOuca2x.hh"
38 #include "XrdOuc/XrdOucEnv.hh"
39 #include "XrdOuc/XrdOucLogging.hh"
41 #include "XrdOuc/XrdOucStream.hh"
42 #include "XrdOuc/XrdOucUtils.hh"
43 
44 #include "XrdSys/XrdSysError.hh"
45 #include "XrdSys/XrdSysFD.hh"
46 #include "XrdSys/XrdSysLogging.hh"
47 #include "XrdSys/XrdSysLogPI.hh"
48 #include "XrdSys/XrdSysPthread.hh"
49 
50 /******************************************************************************/
51 /* T h r e a d I n t e r f a c e s */
52 /******************************************************************************/
53 
54 namespace
55 {
56 int cseLvl = 0;
57 int stdErr = 0;
58 
59 struct dbgHdr
60  {char theDate[6]; // yymmdd
61  char sep1; // single space
62  char theHH[2]; // hh
63  char colon1; // :
64  char theMM[2]; // mm
65  char colon2; // :
66  char theSS[2]; // SS
67  };
68 
69 bool BadHdr(dbgHdr *dLine)
70  {if (dLine->sep1 != ' ' || dLine->colon1 != ':' || dLine->colon2 != ':')
71  return true;
72 
73  if (dLine->theHH[0] < '0' || dLine->theHH[0] > '2'
74  || dLine->theHH[1] < '0' || dLine->theHH[0] > '3'
75  || dLine->theMM[0] < '0' || dLine->theMM[0] > '5'
76  || dLine->theMM[1] < '0' || dLine->theMM[1] > '9'
77  || dLine->theSS[0] < '0' || dLine->theSS[0] > '5'
78  || dLine->theSS[1] < '0' || dLine->theSS[1] > '9') return true;
79 
80  for (int i = 0; i < 6; i++)
81  if (dLine->theDate[i] < '0' || dLine->theDate[i] > '9') return true;
82 
83  return false;
84  }
85 
86 
87 void *LoggingStdErr(void *carg)
88  {(void)carg;
89  XrdOucStream seStream;
90  struct timeval seTime = {0,0};
91  struct iovec ioV;
92 
93  seStream.Attach(stdErr, 4096);
94  do {if ((ioV.iov_base = seStream.GetLine()))
95  {ioV.iov_len = strlen((const char *)ioV.iov_base);
96  if (cseLvl == 1)
97  {if (ioV.iov_len < (int)sizeof(dbgHdr)
98  || BadHdr((dbgHdr *)ioV.iov_base)) continue;
99  }
100  XrdSysLogging::Forward(seTime, 0, &ioV, 1);
101  }
102  } while(true);
103  return 0;
104  }
105 }
106 
107 /******************************************************************************/
108 /* c o n f i g L o g */
109 /******************************************************************************/
110 
113 {
114  struct tmpstr {char *arg; char *arg2, *arg3;
115  tmpstr(const char *str) : arg(strdup(str)),
116  arg2(0), arg3(0) {}
117  ~tmpstr() {if (arg) free(arg);
118  if (arg2) free(arg2);
119  if (arg3) free(arg3);
120  }
121  };
122 
123  static XrdVERSIONINFODEF(myVersion, XrdLogConfig, XrdVNUMBER, XrdVERSION);
124  XrdSysLogging::Parms logParms;
125  char *logPI = 0, *logFN = 0;
126  int argc;
127 
128 // Check for stderr output
129 //
130  if (!strcmp(logInfo.logArg, "-")) return true;
131  tmpstr opt(logInfo.logArg);
132 
133 // Check if this specified a plugin
134 //
135  if (*opt.arg == '@')
136  {char *parms = index(opt.arg, ',');
137  logPI = opt.arg+1;
138  if (!(*logPI))
139  {eDest.Emsg("Config", "Log plugin library not specified.");
140  return false;
141  }
142  if (parms)
143  {char *eol, *pval;
144  int rc;
145  opt.arg3 = strdup(parms); *parms = 0; parms = opt.arg3;
146  if ((pval = varVal(",bsz=", parms, eol, ',')))
147  {long long bsz;
148  rc = XrdOuca2x::a2sz(eDest,"-l bsz",pval,&bsz,0,1048576);
149  if (eol) *eol = ',';
150  if (rc < 0) return false;
151  if (bsz && bsz < 8192) bsz = 8192;
152  logParms.bufsz = static_cast<int>(bsz);
153  }
154  if ((pval = varVal(",cse=", parms, eol, ',')))
155  {rc = XrdOuca2x::a2i(eDest,"-l cse",pval,&cseLvl,0,2);
156  if (eol) *eol = ',';
157  if (rc < 0) return false;
158  }
159  logFN = varVal(",logfn=", parms, eol, ',');
160  }
161  } else logFN = opt.arg;
162 
163 // Handle any logfile name
164 //
165  if (logFN)
166  { if (*logFN == '=')
167  {if (*(logFN+1) == '\0')
168  {eDest.Emsg("Config", "Logfile name not specified.");
169  return false;
170  }
171  logParms.logfn = ++logFN;
172  }
173  else if (strcmp(logFN, "-"))
174  {if (!(logFN = XrdOucUtils::subLogfn(eDest,logInfo.iName,strdup(logFN))))
175  return false;
176  logParms.logfn = opt.arg2 = logFN;
177  }
178  else logParms.logfn = logFN;
179  }
180 
181 // Handle plugin, if any
182 //
183  if (logPI)
184  {XrdSysLogPInit_t logPInit;
185  XrdOucPinLoader lpiLib(&eDest, &myVersion, "logging", logPI);
186  char **lpiArgs = configLPIArgs(logInfo.xrdEnv, argc);
187  if (!(logPInit = (XrdSysLogPInit_t)lpiLib.Resolve("XrdSysLogPInit")))
188  {eDest.Emsg("Config","Unable to find logging plugin object in",logPI);
189  lpiLib.Unload();
190  return false;
191  }
192  if (!(logParms.logpi = (*logPInit)(logInfo.cfgFn, lpiArgs, argc)))
193  {eDest.Emsg("Config", "Logging plugin initialization failed.");
194  lpiLib.Unload();
195  return false;
196  }
197  }
198 
199 // Now complete logging configuration
200 //
201  logParms.keepV = logInfo.keepV;
202  logParms.hiRes = logInfo.hiRes;
203  if (!XrdSysLogging::Configure(*(eDest.logger()), logParms))
204  {eDest.Emsg("Config", "Log configuration failed.");
205  return false;
206  }
207 
208 // Export the directory where the log file exists. We can modify the logfn
209 // as it should have been copied. Note logFN is the same as logParms.logfn.
210 //
211 
212  if (logFN && (logPI = rindex(logFN,'/'))) *(logPI+1) = '\0';
213  else logParms.logfn = "./";
214  XrdOucEnv::Export("XRDLOGDIR", logParms.logfn);
215 
216 // If there is a plugin but alternate output has not been specified, then we
217 // must capture stderr output and feed it to the logging plugin.
218 //
219  if (logPI && !logFN && cseLvl)
220  {pthread_t tid;
221  int pipeFD[2], dupStdErr = XrdSysFD_Dup(STDERR_FILENO);
222  if (dupStdErr < 0 || XrdSysFD_Pipe(pipeFD) < 0
223  || XrdSysFD_Dup2(pipeFD[1], STDERR_FILENO) < 0)
224  {eDest.Emsg("Config",errno, "creating a pipe to capture stderr.");
225  close(dupStdErr);
226  return false;
227  }
228  close(pipeFD[1]);
229  if (XrdSysThread::Run(&tid,LoggingStdErr,(void *)0,0,"stderr router"))
230  {XrdSysFD_Dup2(dupStdErr, STDERR_FILENO);
231  eDest.Emsg("Config", errno, "start stderr router");
232  close(pipeFD[0]); close(dupStdErr); return false;
233  }
234  stdErr = pipeFD[0];
235  close(dupStdErr);
236  }
237 
238 
239 // All done
240 //
241  return true;
242 }
243 
244 /******************************************************************************/
245 /* Private: c o n f i g L P I A r g s */
246 /******************************************************************************/
247 
248 char **XrdOucLogging::configLPIArgs(XrdOucEnv *envP, int &argc)
249 {
250  static char theLPI[] = {'l', 'o', 'g', 0};
251  static char *dfltArgv[] = {0, 0};
252  char **lpiArgv = 0;
253 
254 // Find our arguments, if any
255 //
256  if (envP && (lpiArgv = (char **)envP->GetPtr("xrdlog.argv**")))
257  argc = envP->GetInt("xrdlog.argc");
258 
259 // Verify that we have some and substitute if not
260 //
261  if (!lpiArgv || argc < 1)
262  {if (!envP || !(dfltArgv[0] = (char *)envP->GetPtr("argv[0]")))
263  dfltArgv[0] = theLPI;
264  lpiArgv = dfltArgv;
265  argc = 1;
266  }
267 
268 // Return the argv pointer
269 //
270  return lpiArgv;
271 }
272 
273 /******************************************************************************/
274 /* Private: v a r V a l */
275 /******************************************************************************/
276 
277 char *XrdOucLogging::varVal(const char *var, char *line, char *&eol, char delim)
278 {
279 // Find variable in the line
280 //
281  char *result = strstr(line, var);
282  if (!result) return 0;
283 
284 // Push up to the value and find the end
285 //
286  result += strlen(var);
287  if (!delim) eol = 0;
288  else if ((eol = index(result, delim))) *eol = 0;
289 
290 // All done
291 //
292  return result;
293 }
static XrdSysError eDest(0,"crypto_")
#define close(a)
Definition: XrdPosix.hh:43
XrdSysLogPI_t(* XrdSysLogPInit_t)(const char *cfgn, char **argv, int argc)
Definition: XrdSysLogPI.hh:77
long GetInt(const char *varname)
Definition: XrdOucEnv.cc:253
static int Export(const char *Var, const char *Val)
Definition: XrdOucEnv.cc:188
void * GetPtr(const char *varname)
Definition: XrdOucEnv.cc:281
static bool configLog(XrdSysError &eDest, configLogInfo &logInfo)
void * Resolve(const char *symbl, int mcnt=1)
void Unload(bool dodel=false)
char * GetLine()
int Attach(int FileDescriptor, int bsz=2047)
static char * subLogfn(XrdSysError &eDest, const char *inst, char *logfn)
static int a2i(XrdSysError &, const char *emsg, const char *item, int *val, int minv=-1, int maxv=-1)
Definition: XrdOuca2x.cc:45
static int a2sz(XrdSysError &, const char *emsg, const char *item, long long *val, long long minv=-1, long long maxv=-1)
Definition: XrdOuca2x.cc:257
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
XrdSysLogger * logger(XrdSysLogger *lp=0)
Definition: XrdSysError.hh:141
static bool Forward(struct timeval mtime, unsigned long tID, struct iovec *iov, int iovcnt)
static bool Configure(XrdSysLogger &logr, Parms &parms)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
XrdVersionInfo myVersion
XrdVERSIONINFODEF(myVersion, cmsclient, XrdVNUMBER, XrdVERSION)
XrdOucEnv * envP
Definition: XrdPss.cc:109
Parameters to be passed to configure.
XrdSysLogPI_t logpi
-> log plugin object or nil if none
int keepV
log keep argument
const char * logfn
-> log file name or nil if none.
bool hiRes
log using high resolution timestamp
int bufsz
size of message buffer, -1 default, or 0