XRootD
XrdStats.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S t a t s . 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 Department 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 <cstdio>
31 #include <cstdlib>
32 #include <sys/time.h>
33 #include <sys/resource.h>
34 #include <sys/uio.h>
35 
36 #include "XrdVersion.hh"
37 #include "Xrd/XrdBuffer.hh"
38 #include "Xrd/XrdJob.hh"
39 #include "Xrd/XrdLink.hh"
40 #include "Xrd/XrdMonitor.hh"
41 #include "Xrd/XrdPoll.hh"
42 #include "Xrd/XrdProtLoad.hh"
43 #include "Xrd/XrdScheduler.hh"
44 #include "Xrd/XrdStats.hh"
45 #include "XrdOuc/XrdOucEnv.hh"
46 #include "XrdNet/XrdNetMsg.hh"
47 #include "XrdSys/XrdSysPlatform.hh"
48 #include "XrdSys/XrdSysTimer.hh"
49 
50 /******************************************************************************/
51 /* S t a t i c O b j e c t s */
52 /******************************************************************************/
53 
54  long XrdStats::tBoot = static_cast<long>(time(0));
55 
56 /******************************************************************************/
57 /* L o c a l C l a s s X r d S t a t s J o b */
58 /******************************************************************************/
59 
61 {
62 public:
63 
64  void DoIt() {Stats->Report();
65  Sched->Schedule((XrdJob *)this, time(0)+iVal);
66  }
67 
68  XrdStatsJob(XrdScheduler *schP, XrdStats *sP, int iV)
69  : XrdJob("stats reporter"),
70  Sched(schP), Stats(sP), iVal(iV)
71  {Sched->Schedule((XrdJob *)this, time(0)+iVal);}
73 private:
74 XrdScheduler *Sched;
75 XrdStats *Stats;
76 int iVal;
77 };
78 
79 /******************************************************************************/
80 /* C o n s t r c u t o r */
81 /******************************************************************************/
82 
84  const char *hname, int port,
85  const char *iname, const char *pname, const char *site)
86 {
87  const char *head =
88  "<statistics tod=\"%%ld\" ver=\"" XrdVERSION "\" src=\"%s:%d\" "
89  "tos=\"%ld\" pgm=\"%s\" ins=\"%s\" pid=\"%d\" "
90  "site=\"%s\">";
91  Hend = "</statistics>";
92  Htln = strlen(Hend);
93 
94  const char *jead =
95  "{\"statistics\":{\"tod\":%%ld,\"ver\":\"" XrdVERSION "\",\"src\":\"%s:%d\","
96  "\"tos\":%ld,\"pgm\":\"%s\",\"ins\":\"%s\",\"pid\":%d,"
97  "\"site\":\"%s\",";
98  Jend = "}}";
99  Jtln = 2;
100 
101  char myBuff[1024];
102 
103  XrdLog = eP;
104  XrdSched = sP;
105  BuffPool = bP;
106 
107  sprintf(myBuff, head, hname, port, tBoot, pname, iname,
108  static_cast<int>(getpid()), (site ? site : ""));
109  Head = strdup(myBuff);
110 
111  sprintf(myBuff, jead, hname, port, tBoot, pname, iname,
112  static_cast<int>(getpid()), (site ? site : ""));
113  Jead = strdup(myBuff);
114 
115 // Allocate a shared buffer. Buffer use is serialized via the statsMutex.
116 //
117  blen = 64*1024; // 64K which is the largest allowed UDP packet
118  if (posix_memalign((void **)&buff, getpagesize(), blen)) buff = 0;
119 
120  myHost = hname;
121  myName = iname;
122  myPort = port;
123 
124  theMon = new XrdMonitor;
125 }
126 
127 /******************************************************************************/
128 /* E x p o r t */
129 /******************************************************************************/
130 
132 {
133  XrdMonRoll* monRoll = new XrdMonRoll(*theMon);
134  theEnv.PutPtr("XrdMonRoll*", monRoll);
135 }
136 
137 /******************************************************************************/
138 /* I n i t */
139 /******************************************************************************/
140 
141 void XrdStats::Init(char **Dest, int iVal, int xOpts, int jOpts)
142 {
143 
144 // Establish up to two destinations
145 //
146  if (Dest[0]) netDest[0] = new XrdNetMsg(XrdLog, Dest[0]);
147  if (Dest[1]) netDest[1] = new XrdNetMsg(XrdLog, Dest[1]);
148 
149 // Establish auto reporting options
150 //
151  if (!(jOpts & XRD_STATS_ALLJ) && !(xOpts & XRD_STATS_ALLX))
152  xOpts |= XRD_STATS_ALLX; // ALLX includes ALLJ
153  jsonOpts = (jOpts & XRD_STATS_ALLJ) | XRD_STATS_JSON; xmlOpts = xOpts;
154  autoSync = xOpts & XRD_STATS_SYNCA;
155 
156 // Get and schedule a new job to report
157 //
158  if (netDest[0]) new XrdStatsJob(XrdSched, this, iVal);
159  return;
160 }
161 
162 /******************************************************************************/
163 /* R e p o r t */
164 /******************************************************************************/
165 
167 {
168  char udpBuff[64*1024];
169  const char *Data;
170  int theOpts, Dlen;
171 
172 // This is an entry for reporting purposes, establish the sync flag
173 //
174  if (!autoSync || XrdSched->Active() <= 30) theOpts = xmlOpts;
175  else theOpts = xmlOpts & ~XRD_STATS_SYNC;
176 
177 // Now get the statistics in xml format. Note that there is only one buufer
178 // so we lock this code path to protect it. Skip this if no specific reports
179 // in the xml category are requested.
180 //
181  if (theOpts)
182  {statsMutex.Lock();
183  if ((Data = GenStats(Dlen, theOpts)))
184  {netDest[0]->Send(Data, Dlen);
185  if (netDest[1]) netDest[1]->Send(Data, Dlen);
186  }
187  statsMutex.UnLock();
188  }
189 
190 // Check if we have additional data registered via addons and plugins that
191 // we need in JSON format. These are sent as separate udp packets.
192 //
193  theOpts = XrdMonitor::F_JSON;
194  if (jsonOpts & XRD_STATS_ADON) theOpts |= XrdMonitor::X_ADON;
195  if (jsonOpts & XRD_STATS_PLUG) theOpts |= XrdMonitor::X_PLUG;
196  if (!(theOpts & ~XrdMonitor::F_JSON) || !theMon->Registered()) return;
197 
198 // Format the header and setup for sending packets
199 //
200  int hL = sprintf(udpBuff, Jead, time(0));
201  int bL = sizeof(udpBuff) - hL - Jtln - 8;
202  char* bP = udpBuff + hL;
203 
204 // Get each item and send it off
205 //
206  struct iovec ioV[3];
207  ioV[0].iov_base = udpBuff;
208  ioV[0].iov_len = hL;
209  ioV[1].iov_base = bP;
210  ioV[2].iov_base = (void*)Jend;
211  ioV[2].iov_len = Jtln;
212  int uL, sItem = 0;
213  while((uL = theMon->Format(bP, bL, sItem, theOpts)))
214  {ioV[1].iov_len = uL;
215  netDest[0]->Send(ioV, 3);
216  if (netDest[1]) netDest[1]->Send(ioV, 3);
217  }
218 }
219 
220 /******************************************************************************/
221 /* S t a t s */
222 /******************************************************************************/
223 
224 void XrdStats::Stats(XrdStats::CallBack *cbP, int xOpts, int jOpts)
225 {
226  const char *info;
227  int sz, opts;
228 
229 // Note that currently we do not support json for client requests, so we
230 // ignore the jOpts as they should never be set.
231 //
232  opts = xOpts;
233 
234 // Lock the buffer,
235 //
236  statsMutex.Lock();
237 
238 // Obtain the stats, if we have some, do the callback. We currently do not
239 // support return of JSON format as some statistics can't provide it.
240 //
241  if ((info = GenStats(sz, opts))) cbP->Info(info, sz);
242 
243 // Unlock the buffer
244 //
245  statsMutex.UnLock();
246 }
247 
248 /******************************************************************************/
249 /* P r i v a t e M e t h o d s */
250 /******************************************************************************/
251 /******************************************************************************/
252 /* G e n S t a t s */
253 /******************************************************************************/
254 
255 const char *XrdStats::GenStats(int &rsz, int opts) // statsMutex must be locked!
256 {
257  static const char *sgen = "<stats id=\"sgen\">"
258  "<as>%d</as><et>%lu</et><toe>%ld</toe></stats>";
259  static const char *tail = "</statistics>";
260  static const char *snul = "<statistics tod=\"0\" ver=\"" XrdVSTRING "\">"
261  "</statistics>";
262 
263  static const int snulsz = strlen(snul);
264  static const int ovrhed = 256+strlen(sgen)+strlen(tail);
265  XrdSysTimer myTimer;
266  char *bp;
267  int n, bl, sz, do_sync = (opts & XRD_STATS_SYNC ? 1 : 0);
268 
269 // If buffer is not allocated we cannot generate a report (not likely)
270 //
271  if (!(bp = buff)) {rsz = snulsz; return snul;}
272  bl = blen - ovrhed;
273 
274 // Start the time if need be
275 //
276  if (opts & XRD_STATS_SGEN) myTimer.Reset();
277 
278 // Insert the heading
279 //
280  sz = sprintf(buff, Head, static_cast<long>(time(0)));
281  bl -= sz; bp += sz;
282 
283 // Extract out the statistics, as needed
284 //
285  if (opts & XRD_STATS_INFO)
286  {sz = InfoStats(bp, bl, do_sync);
287  bp += sz; bl -= sz;
288  }
289 
290  if (opts & XRD_STATS_BUFF)
291  {sz = BuffPool->Stats(bp, bl, do_sync);
292  bp += sz; bl -= sz;
293  }
294 
295  if (opts & XRD_STATS_LINK)
296  {sz = XrdLink::Stats(bp, bl, do_sync);
297  bp += sz; bl -= sz;
298  }
299 
300  if (opts & XRD_STATS_POLL)
301  {sz = XrdPoll::Stats(bp, bl, do_sync);
302  bp += sz; bl -= sz;
303  }
304 
305  if (opts & XRD_STATS_PROC)
306  {sz = ProcStats(bp, bl, do_sync);
307  bp += sz; bl -= sz;
308  }
309 
310  if (opts & XRD_STATS_PROT)
311  {sz = XrdProtLoad::Statistics(bp, bl, do_sync);
312  bp += sz; bl -= sz;
313  }
314 
315  if (opts & XRD_STATS_SCHD)
316  {sz = XrdSched->Stats(bp, bl, do_sync);
317  bp += sz; bl -= sz;
318  }
319 
320  if (opts & XRD_STATS_SGEN)
321  {unsigned long totTime = 0;
322  myTimer.Report(totTime);
323  sz = snprintf(bp,bl,sgen,do_sync==0,totTime,static_cast<long>(time(0)));
324  bp += sz; bl -= sz;
325  }
326 
327 // Set the type of object we are interested in
328 //
329  int fOpts = 0;
330  if (opts & XRD_STATS_ADON) fOpts |= XrdMonitor::X_ADON;
331  if (opts & XRD_STATS_PLUG) fOpts |= XrdMonitor::X_PLUG;
332  if (fOpts)
333  {int uL, sItem = 0;
334  while(bl > 0 && (uL = theMon->Format(bp, bl, sItem, fOpts)))
335  {bp += uL; bl -= uL;}
336  }
337 
338  sz = bp - buff;
339  if (bl > 0) n = strlcpy(bp, tail, bl);
340  else n = 0;
341  rsz = sz + (n >= bl ? bl : n);
342  return buff;
343 }
344 
345 /******************************************************************************/
346 
347 
348 void XrdStats::GenStats(std::vector<struct iovec>& ioVec, int opts)
349 {
350  const char* sTail;
351  char *sbP, sBuff[64*1024]; // Maximum size of UDP packet
352  std::vector<struct iovec> ioV;
353  int sTLen, sbFree, sdSZ, fOpts, sItem = 0;
354 
355 // Insert the header in the buffer
356 //
357  if (opts & XRD_STATS_JSON)
358  {int Jlen = sprintf(sBuff, Jead, time(0));
359  sdSZ = sbFree = sizeof(sBuff) - Jlen - 64; // Generous extra for tail
360  sbP = sBuff + Jlen;
361  sTail = Jend;
362  sTLen = Jtln;
363  fOpts = XrdMonitor::F_JSON;
364  } else {
365  int Hlen = sprintf(sBuff, Head, time(0));
366  sdSZ = sbFree = sizeof(sBuff) - Hlen - 64; // Generous extra for tail
367  sbP = sBuff + Hlen;
368  sTail = Hend;
369  sTLen = Htln;
370  fOpts = 0;
371  }
372 
373 // Set the type of object we are interested in
374 //
375  if (opts & XRD_STATS_ADON) fOpts |= XrdMonitor::X_ADON;
376  if (opts & XRD_STATS_PLUG) fOpts |= XrdMonitor::X_PLUG;
377 
378 // Generate all plugin statistics, one at a time
379 //
380  while((sdSZ = theMon->Format(sbP, sbFree, sItem, fOpts)))
381  {if (sdSZ > 0 && sdSZ <= sbFree)
382  {char* bP = sbP + sdSZ;
383  struct iovec ioV;
384  strcpy(bP, sTail);
385  strcpy(bP+sTLen, "\n");
386  bP++;
387  ioV.iov_base = strdup(sBuff);
388  ioV.iov_len = bP - sBuff + sTLen;
389  ioVec.push_back(ioV);
390  }
391  }
392 }
393 
394 /******************************************************************************/
395 /* I n f o S t a t s */
396 /******************************************************************************/
397 
398 int XrdStats::InfoStats(char *bfr, int bln, int do_sync)
399 {
400  static const char statfmt[] = "<stats id=\"info\"><host>%s</host>"
401  "<port>%d</port><name>%s</name></stats>";
402 
403 // Check if actual length wanted
404 //
405  if (!bfr) return sizeof(statfmt)+24 + strlen(myHost);
406 
407 // Format the statistics
408 //
409  return snprintf(bfr, bln, statfmt, myHost, myPort, myName);
410 }
411 
412 /******************************************************************************/
413 /* P r o c S t a t s */
414 /******************************************************************************/
415 
416 int XrdStats::ProcStats(char *bfr, int bln, int do_sync)
417 {
418  static const char statfmt[] = "<stats id=\"proc\">"
419  "<usr><s>%lld</s><u>%lld</u></usr>"
420  "<sys><s>%lld</s><u>%lld</u></sys>"
421  "</stats>";
422  struct rusage r_usage;
423  long long utime_sec, utime_usec, stime_sec, stime_usec;
424 // long long ru_maxrss, ru_majflt, ru_nswap, ru_inblock, ru_oublock;
425 // long long ru_msgsnd, ru_msgrcv, ru_nsignals;
426 
427 // Check if actual length wanted
428 //
429  if (!bfr) return sizeof(statfmt)+16*13;
430 
431 // Get the statistics
432 //
433  if (getrusage(RUSAGE_SELF, &r_usage)) return 0;
434 
435 // Convert fields to correspond to the format we are using. Commented out fields
436 // are either not uniformaly reported or are incorrectly reported making them
437 // useless across multiple platforms.
438 //
439 //
440  utime_sec = static_cast<long long>(r_usage.ru_utime.tv_sec);
441  utime_usec = static_cast<long long>(r_usage.ru_utime.tv_usec);
442  stime_sec = static_cast<long long>(r_usage.ru_stime.tv_sec);
443  stime_usec = static_cast<long long>(r_usage.ru_stime.tv_usec);
444 // ru_maxrss = static_cast<long long>(r_usage.ru_maxrss);
445 // ru_majflt = static_cast<long long>(r_usage.ru_majflt);
446 // ru_nswap = static_cast<long long>(r_usage.ru_nswap);
447 // ru_inblock = static_cast<long long>(r_usage.ru_inblock);
448 // ru_oublock = static_cast<long long>(r_usage.ru_oublock);
449 // ru_msgsnd = static_cast<long long>(r_usage.ru_msgsnd);
450 // ru_msgrcv = static_cast<long long>(r_usage.ru_msgrcv);
451 // ru_nsignals = static_cast<long long>(r_usage.ru_nsignals);
452 
453 // Format the statistics
454 //
455  return snprintf(bfr, bln, statfmt,
456  utime_sec, utime_usec, stime_sec, stime_usec
457 // ru_maxrss, ru_majflt, ru_nswap, ru_inblock, ru_oublock,
458 // ru_msgsnd, ru_msgrcv, ru_nsignals
459  );
460 }
struct myOpts opts
#define XRD_STATS_POLL
Definition: XrdStats.hh:44
#define XRD_STATS_ADON
Definition: XrdStats.hh:37
#define XRD_STATS_JSON
Definition: XrdStats.hh:52
#define XRD_STATS_SYNC
Definition: XrdStats.hh:49
#define XRD_STATS_INFO
Definition: XrdStats.hh:40
#define XRD_STATS_LINK
Definition: XrdStats.hh:42
#define XRD_STATS_BUFF
Definition: XrdStats.hh:41
#define XRD_STATS_SYNCA
Definition: XrdStats.hh:50
#define XRD_STATS_PLUG
Definition: XrdStats.hh:43
#define XRD_STATS_SCHD
Definition: XrdStats.hh:47
#define XRD_STATS_ALLX
Definition: XrdStats.hh:39
#define XRD_STATS_PROT
Definition: XrdStats.hh:46
#define XRD_STATS_PROC
Definition: XrdStats.hh:45
#define XRD_STATS_SGEN
Definition: XrdStats.hh:48
#define XRD_STATS_ALLJ
Definition: XrdStats.hh:38
size_t strlcpy(char *dst, const char *src, size_t sz)
int Stats(char *buff, int blen, int do_sync=0)
Definition: XrdBuffer.cc:323
Definition: XrdJob.hh:43
int Format(char *buff, int bsize, int &item, int opts=0)
Definition: XrdMonitor.cc:64
bool Registered()
Definition: XrdMonitor.hh:54
int Send(const char *buff, int blen=0, const char *dest=0, int tmo=-1)
Definition: XrdNetMsg.cc:127
void PutPtr(const char *varname, void *value)
Definition: XrdOucEnv.cc:298
static int Stats(char *buff, int blen, int do_sync=0)
Definition: XrdPoll.cc:332
static int Statistics(char *buff, int blen, int do_sync=0)
Definition: XrdProtLoad.cc:256
int Stats(char *buff, int blen, int do_sync=0)
void Schedule(XrdJob *jp)
void DoIt()
Definition: XrdStats.cc:64
~XrdStatsJob()
Definition: XrdStats.cc:72
XrdStatsJob(XrdScheduler *schP, XrdStats *sP, int iV)
Definition: XrdStats.cc:68
virtual void Info(const char *data, int dlen)=0
void Init(char **Dest, int iVal=600, int xOpts=0, int jOpts=0)
Definition: XrdStats.cc:141
XrdStats(XrdSysError *eP, XrdScheduler *sP, XrdBuffManager *bP, const char *hn, int port, const char *in, const char *pn, const char *sn)
Definition: XrdStats.cc:83
void Report()
Definition: XrdStats.cc:166
void Export(XrdOucEnv &env)
Definition: XrdStats.cc:131
virtual void Stats(XrdStats::CallBack *InfoBack, int xOpts, int jOpts=0)
Definition: XrdStats.cc:224
void Reset()
Definition: XrdSysTimer.hh:61
unsigned long Report(double &)
Definition: XrdSysTimer.cc:100
XrdOucEnv theEnv
XrdBuffManager BuffPool
Definition: XrdGlobals.cc:51