XRootD
Loading...
Searching...
No Matches
XrdSysLogging.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d S y s 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/*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 <stddef.h>
31#include <cstdlib>
32#include <unistd.h>
33#include <cstdio>
34
35#include "XrdSys/XrdSysE2T.hh"
39
40/******************************************************************************/
41/* S t a t i c O b j e c t s */
42/******************************************************************************/
43
44namespace
45{
46static const int buffOvhd = 8;
47
48XrdSysMutex msgMutex;
49XrdSysSemaphore msgAlert(0);
50XrdSysLogPI_t piLogger = 0;
51char *pendMsg = 0; // msg to be processed, if nil means none
52char *lastMsg = 0; // last msg in the processing queue
53char *buffOrg = 0; // Base address of global message buffer
54char *buffBeg = 0; // buffOrg + overhead
55char *buffEnd = 0; // buffOrg + size of buffer
56struct timeval todLost; // time last message was lost
57int numLost = 0; // Number of messages lost
58bool logDone = false;
59bool doSync = false;
60
61static const int syncBSZ = 8192;
62};
63
64pthread_t XrdSysLogging::lpiTID;
65bool XrdSysLogging::lclOut = false;
66bool XrdSysLogging::rmtOut = false;
67
68/******************************************************************************/
69/* C o n f i g u r e */
70/******************************************************************************/
71
73{
74 char eBuff[256];
75 int rc;
76
77// Set logger parameters
78//
79 if (parms.hiRes) logr.setHiRes();
80
81// If we are going to send output to a local destination, configure it.
82//
83 if (parms.logfn)
84 {if (strcmp(parms.logfn, "-") && (rc=logr.Bind(parms.logfn,parms.keepV)))
85 {sprintf(eBuff, "Error %d (%s) binding to log file %s.\n",
86 -rc, XrdSysE2T(-rc), parms.logfn);
87 return EMsg(logr, eBuff);
88 }
89 lclOut = true;
90 }
91
92// If we are not sending output to a remote destination, we are done
93//
94 if (!parms.logpi) {lclOut = true; return true;}
95 piLogger= parms.logpi;
96 logDone = !lclOut;
97 rmtOut = true;
98
99// We have a plugin, setup the synchronous case if so desired
100//
101 if (!parms.bufsz)
102 {logr.setForwarding(true);
103 doSync = true;
104 return true;
105 }
106
107// Allocate a log buffer
108//
109 int bsz = (parms.bufsz < 0 ? 65536 : parms.bufsz);
110 rc = posix_memalign((void **)&buffOrg, getpagesize(), bsz);
111 if (rc != 0 || !buffOrg) return EMsg(logr, "Unable to allocate log buffer!\n");
112
113 buffBeg = buffOrg + buffOvhd;
114 buffEnd = buffOrg + bsz;
115
116// Start the forwarding thread
117//
118 if (XrdSysThread::Run(&lpiTID, Send2PI, (void *)0, 0, "LogPI handler"))
119 {sprintf(eBuff, "Error %d (%s) starting LogPI handler.\n",
120 errno, XrdSysE2T(errno));
121 return EMsg(logr, eBuff);
122 }
123
124// We are all done
125//
126 logr.setForwarding(true);
127 return true;
128}
129
130/******************************************************************************/
131/* Private: C o p y T r u n c */
132/******************************************************************************/
133
134int XrdSysLogging::CopyTrunc(char *mbuff, struct iovec *iov, int iovcnt)
135{
136 char *mbP = mbuff;
137 int segLen, bLeft = syncBSZ - 1;
138
139// Copy message with truncation
140//
141 for (int i = 0; i < iovcnt; i++)
142 {segLen = iov[i].iov_len;
143 if (segLen >= bLeft) segLen = bLeft;
144 memcpy(mbP, iov[i].iov_base, segLen);
145 mbP += segLen; bLeft -= segLen;
146 if (bLeft <= 0) break;
147 }
148 *mbP = 0;
149
150// Return actual length
151//
152 return mbP - mbuff;
153}
154
155/******************************************************************************/
156/* Private: E M s g */
157/******************************************************************************/
158
159bool XrdSysLogging::EMsg(XrdSysLogger &logr, const char *msg)
160{
161 struct iovec iov[] = {{0,0}, {(char *)msg,0}};
162
163 iov[1].iov_len = strlen((const char *)iov[1].iov_base);
164 logr.Put(2, iov);
165 return false;
166}
167
168/******************************************************************************/
169/* F o r w a r d */
170/******************************************************************************/
171
172bool XrdSysLogging::Forward(struct timeval mtime, unsigned long tID,
173 struct iovec *iov, int iovcnt)
174{
175 MsgBuff *theMsg;
176 char *fence, *freeMsg, *msgText;
177 int dwords, msgLen = 0;
178 bool doPost = false;
179
180// Calculate the message length
181//
182 for (int i = 0; i < iovcnt; i++) msgLen += iov[i].iov_len;
183
184// If we are doing synchronous forwarding, do so now (we do not get a lock)
185//
186 if (doSync)
187 {char *mbP, mbuff[syncBSZ];
188 if (msgLen >= syncBSZ) msgLen = CopyTrunc(mbuff, iov, iovcnt);
189 else {mbP = mbuff;
190 for (int i = 0; i < iovcnt; i++)
191 {memcpy(mbP, iov[i].iov_base, iov[i].iov_len);
192 mbP += iov[i].iov_len;
193 }
194 *mbP = 0;
195 }
196 (*piLogger)(mtime, tID, mbuff, msgLen);
197 return logDone;
198 }
199
200// Serialize remainder of code
201//
202 msgMutex.Lock();
203
204// If the message is excessively long, treat it as a lost message
205//
206 if (msgLen > maxMsgLen)
207 {todLost = mtime;
208 numLost++;
209 msgMutex.UnLock();
210 return logDone;
211 }
212
213// Get the actual doublewords bytes we need (account for null byte in the msg).
214// We need to increase the size by the header size if there are outsanding
215// lost messages.
216//
217 dwords = msgLen+8 + sizeof(MsgBuff);
218 if (numLost) dwords += sizeof(MsgBuff);
219 dwords = dwords/8;
220
221// Compute the allocation fence. The choices are as follows:
222// a) When pendMsg is present then the fence is the end of the buffer if
223// lastMsg >= pendMsg and pendMsg otherwise.
224// b) When pendMsg is nil then we can reset the buffer pointers so that the
225// fence is the end of the buffer.
226//
227 if (pendMsg)
228 {freeMsg = lastMsg + ((MsgBuff *)lastMsg)->buffsz*8;
229 fence = (lastMsg >= pendMsg ? buffEnd : pendMsg);
230 } else {
231 freeMsg = buffBeg;
232 fence = buffEnd;
233 lastMsg = 0;
234 doPost = true;
235 }
236
237// Check if there is room for this message. If not, count this as a lost
238// message and tell the caller full forwarding did not happen.
239//
240 if ((freeMsg + (dwords*8)) > fence)
241 {todLost = mtime;
242 numLost++;
243 msgMutex.UnLock();
244 return logDone;
245 }
246
247// We can allocate everything. So, check if we will be inserting a lost
248// message entry here. We preallocated this above when numLost != 0;
249//
250 if (numLost)
251 {theMsg = (MsgBuff *)freeMsg;
252 theMsg->msgtod = mtime;
253 theMsg->tID = tID;
254 theMsg->buffsz = mbDwords;
255 theMsg->msglen = -numLost;
256 if (lastMsg) ((MsgBuff *)lastMsg)->next = freeMsg - buffOrg;
257 lastMsg = freeMsg;
258 freeMsg += msgOff;
259 }
260
261// Insert the message
262//
263 theMsg = (MsgBuff *)freeMsg;
264 theMsg->msgtod = mtime;
265 theMsg->tID = tID;
266 theMsg->next = 0;
267 theMsg->buffsz = dwords;
268 theMsg->msglen = msgLen;
269 if (lastMsg) ((MsgBuff *)lastMsg)->next = freeMsg - buffOrg;
270 lastMsg = freeMsg;
271
272// Copy the message text into the buffer
273//
274 msgText = freeMsg + msgOff;
275 for (int i = 0; i < iovcnt; i++)
276 {memcpy(msgText, iov[i].iov_base, iov[i].iov_len);
277 msgText += iov[i].iov_len;
278 }
279 *msgText = 0;
280
281// If we need to write this to another log file do so here.
282//
283
284// Do final post processing (release the lock prior to posting)
285//
286 if (doPost) pendMsg = freeMsg;
287 msgMutex.UnLock();
288 if (doPost) msgAlert.Post();
289 return logDone;
290}
291
292/******************************************************************************/
293/* Private: g e t M s g */
294/******************************************************************************/
295
296XrdSysLogging::MsgBuff *XrdSysLogging::getMsg(char **msgTxt, bool cont)
297{
298 XrdSysMutexHelper msgHelp(msgMutex);
299 MsgBuff *theMsg;
300
301// If we got incorrectly posted, ignore this call
302//
303 if (!pendMsg) return 0;
304
305// Check if this is a continuation. If so, skip to next message. If there is no
306// next message, clear the pendMsg pointer to indicate we stopped pulling any
307// messages (we will get posted when another message arrives).
308//
309 if (cont)
310 {if (((MsgBuff *)pendMsg)->next)
311 pendMsg = buffOrg + ((MsgBuff *)pendMsg)->next;
312 else pendMsg = 0;
313 }
314
315// Return the message
316//
317 theMsg = (MsgBuff *)pendMsg;
318 *msgTxt = pendMsg + msgOff;
319 return theMsg;
320}
321
322/******************************************************************************/
323/* Private: S e n d 2 P I */
324/******************************************************************************/
325
326void *XrdSysLogging::Send2PI(void *arg)
327{
328 (void)arg;
329 MsgBuff *theMsg;
330 char *msgTxt, lstBuff[80];
331 int msgLen;
332 bool cont;
333
334// Infinit loop feeding the logger plugin
335//
336do{msgAlert.Wait();
337 cont = false;
338 while((theMsg = getMsg(&msgTxt, cont)))
339 {if ((msgLen = theMsg->msglen) < 0)
340 {int n = -msgLen; // Note we will never overflow lstBuff!
341 msgLen = snprintf(lstBuff, sizeof(lstBuff), "%d message%s lost!",
342 n, (n == 1 ? "" : "s"));
343 msgTxt = lstBuff;
344 }
345 (*piLogger)(theMsg->msgtod, theMsg->tID, msgTxt, msgLen);
346 cont = true;
347 }
348 } while(true);
349
350// Here to keep the compiler happy
351//
352 return (void *)0;
353}
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
void(* XrdSysLogPI_t)(struct timeval const &mtime, unsigned long tID, const char *msg, int mlen)
void setHiRes()
Set log file timstamp to high resolution (hh:mm:ss.uuuu).
void Put(int iovcnt, struct iovec *iov)
static void setForwarding(bool onoff)
Set call-out to logging plug-in on or off.
int Bind(const char *path, int lfh=0)
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)
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