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.
179 //
180  statsMutex.Lock();
181  if ((Data = GenStats(Dlen, theOpts)))
182  {netDest[0]->Send(Data, Dlen);
183  if (netDest[1]) netDest[1]->Send(Data, Dlen);
184  }
185  statsMutex.UnLock();
186 
187 // Check if we have additional data registered via addons and plugins that
188 // we need in JSON format. These are sent as separate udp packets.
189 //
190  theOpts = XrdMonitor::F_JSON;
191  if (jsonOpts & XRD_STATS_ADON) theOpts |= XrdMonitor::X_ADON;
192  if (jsonOpts & XRD_STATS_PLUG) theOpts |= XrdMonitor::X_PLUG;
193  if (!(theOpts & ~XrdMonitor::F_JSON) || !theMon->Registered()) return;
194 
195 // Format the header and setup for sending packets
196 //
197  int hL = sprintf(udpBuff, Jead, time(0));
198  int bL = sizeof(udpBuff) - hL - Jtln - 8;
199  char* bP = udpBuff + hL;
200 
201 // Get each item and send it off
202 //
203  struct iovec ioV[3];
204  ioV[0].iov_base = udpBuff;
205  ioV[0].iov_len = hL;
206  ioV[1].iov_base = bP;
207  ioV[2].iov_base = (void*)Jend;
208  ioV[2].iov_len = Jtln;
209  int uL, sItem = 0;
210  while((uL = theMon->Format(bP, bL, sItem, theOpts)))
211  {ioV[1].iov_len = uL;
212  netDest[0]->Send(ioV, 3);
213  if (netDest[1]) netDest[1]->Send(ioV, 3);
214  }
215 }
216 
217 /******************************************************************************/
218 /* S t a t s */
219 /******************************************************************************/
220 
221 void XrdStats::Stats(XrdStats::CallBack *cbP, int xOpts, int jOpts)
222 {
223  const char *info;
224  int sz, opts;
225 
226 // Note that currently we do not support json for client requests, so we
227 // ignore the jOpts as they should never be set.
228 //
229  opts = xOpts;
230 
231 // Lock the buffer,
232 //
233  statsMutex.Lock();
234 
235 // Obtain the stats, if we have some, do the callback. We currently do not
236 // support return of JSON format as some statistics can't provide it.
237 //
238  if ((info = GenStats(sz, opts))) cbP->Info(info, sz);
239 
240 // Unlock the buffer
241 //
242  statsMutex.UnLock();
243 }
244 
245 /******************************************************************************/
246 /* P r i v a t e M e t h o d s */
247 /******************************************************************************/
248 /******************************************************************************/
249 /* G e n S t a t s */
250 /******************************************************************************/
251 
252 const char *XrdStats::GenStats(int &rsz, int opts) // statsMutex must be locked!
253 {
254  static const char *sgen = "<stats id=\"sgen\">"
255  "<as>%d</as><et>%lu</et><toe>%ld</toe></stats>";
256  static const char *tail = "</statistics>";
257  static const char *snul = "<statistics tod=\"0\" ver=\"" XrdVSTRING "\">"
258  "</statistics>";
259 
260  static const int snulsz = strlen(snul);
261  static const int ovrhed = 256+strlen(sgen)+strlen(tail);
262  XrdSysTimer myTimer;
263  char *bp;
264  int n, bl, sz, do_sync = (opts & XRD_STATS_SYNC ? 1 : 0);
265 
266 // If buffer is not allocated we cannot generate a report (not likely)
267 //
268  if (!(bp = buff)) {rsz = snulsz; return snul;}
269  bl = blen - ovrhed;
270 
271 // Start the time if need be
272 //
273  if (opts & XRD_STATS_SGEN) myTimer.Reset();
274 
275 // Insert the heading
276 //
277  sz = sprintf(buff, Head, static_cast<long>(time(0)));
278  bl -= sz; bp += sz;
279 
280 // Extract out the statistics, as needed
281 //
282  if (opts & XRD_STATS_INFO)
283  {sz = InfoStats(bp, bl, do_sync);
284  bp += sz; bl -= sz;
285  }
286 
287  if (opts & XRD_STATS_BUFF)
288  {sz = BuffPool->Stats(bp, bl, do_sync);
289  bp += sz; bl -= sz;
290  }
291 
292  if (opts & XRD_STATS_LINK)
293  {sz = XrdLink::Stats(bp, bl, do_sync);
294  bp += sz; bl -= sz;
295  }
296 
297  if (opts & XRD_STATS_POLL)
298  {sz = XrdPoll::Stats(bp, bl, do_sync);
299  bp += sz; bl -= sz;
300  }
301 
302  if (opts & XRD_STATS_PROC)
303  {sz = ProcStats(bp, bl, do_sync);
304  bp += sz; bl -= sz;
305  }
306 
307  if (opts & XRD_STATS_PROT)
308  {sz = XrdProtLoad::Statistics(bp, bl, do_sync);
309  bp += sz; bl -= sz;
310  }
311 
312  if (opts & XRD_STATS_SCHD)
313  {sz = XrdSched->Stats(bp, bl, do_sync);
314  bp += sz; bl -= sz;
315  }
316 
317  if (opts & XRD_STATS_SGEN)
318  {unsigned long totTime = 0;
319  myTimer.Report(totTime);
320  sz = snprintf(bp,bl,sgen,do_sync==0,totTime,static_cast<long>(time(0)));
321  bp += sz; bl -= sz;
322  }
323 
324 // Set the type of object we are interested in
325 //
326  int fOpts = 0;
327  if (opts & XRD_STATS_ADON) fOpts |= XrdMonitor::X_ADON;
328  if (opts & XRD_STATS_PLUG) fOpts |= XrdMonitor::X_PLUG;
329  if (fOpts)
330  {int uL, sItem = 0;
331  while(bl > 0 && (uL = theMon->Format(bp, bl, sItem, fOpts)))
332  {bp += uL; bl -= uL;}
333  }
334 
335  sz = bp - buff;
336  if (bl > 0) n = strlcpy(bp, tail, bl);
337  else n = 0;
338  rsz = sz + (n >= bl ? bl : n);
339  return buff;
340 }
341 
342 /******************************************************************************/
343 
344 
345 void XrdStats::GenStats(std::vector<struct iovec>& ioVec, int opts)
346 {
347  const char* sTail;
348  char *sbP, sBuff[64*1024]; // Maximum size of UDP packet
349  std::vector<struct iovec> ioV;
350  int sTLen, sbFree, sdSZ, fOpts, sItem = 0;
351 
352 // Insert the header in the buffer
353 //
354  if (opts & XRD_STATS_JSON)
355  {int Jlen = sprintf(sBuff, Jead, time(0));
356  sdSZ = sbFree = sizeof(sBuff) - Jlen - 64; // Generous extra for tail
357  sbP = sBuff + Jlen;
358  sTail = Jend;
359  sTLen = Jtln;
360  fOpts = XrdMonitor::F_JSON;
361  } else {
362  int Hlen = sprintf(sBuff, Head, time(0));
363  sdSZ = sbFree = sizeof(sBuff) - Hlen - 64; // Generous extra for tail
364  sbP = sBuff + Hlen;
365  sTail = Hend;
366  sTLen = Htln;
367  fOpts = 0;
368  }
369 
370 // Set the type of object we are interested in
371 //
372  if (opts & XRD_STATS_ADON) fOpts |= XrdMonitor::X_ADON;
373  if (opts & XRD_STATS_PLUG) fOpts |= XrdMonitor::X_PLUG;
374 
375 // Generate all plugin statistics, one at a time
376 //
377  while((sdSZ = theMon->Format(sbP, sbFree, sItem, fOpts)))
378  {if (sdSZ > 0 && sdSZ <= sbFree)
379  {char* bP = sbP + sdSZ;
380  struct iovec ioV;
381  strcpy(bP, sTail);
382  strcpy(bP+sTLen, "\n");
383  bP++;
384  ioV.iov_base = strdup(sBuff);
385  ioV.iov_len = bP - sBuff + sTLen;
386  ioVec.push_back(ioV);
387  }
388  }
389 }
390 
391 /******************************************************************************/
392 /* I n f o S t a t s */
393 /******************************************************************************/
394 
395 int XrdStats::InfoStats(char *bfr, int bln, int do_sync)
396 {
397  static const char statfmt[] = "<stats id=\"info\"><host>%s</host>"
398  "<port>%d</port><name>%s</name></stats>";
399 
400 // Check if actual length wanted
401 //
402  if (!bfr) return sizeof(statfmt)+24 + strlen(myHost);
403 
404 // Format the statistics
405 //
406  return snprintf(bfr, bln, statfmt, myHost, myPort, myName);
407 }
408 
409 /******************************************************************************/
410 /* P r o c S t a t s */
411 /******************************************************************************/
412 
413 int XrdStats::ProcStats(char *bfr, int bln, int do_sync)
414 {
415  static const char statfmt[] = "<stats id=\"proc\">"
416  "<usr><s>%lld</s><u>%lld</u></usr>"
417  "<sys><s>%lld</s><u>%lld</u></sys>"
418  "</stats>";
419  struct rusage r_usage;
420  long long utime_sec, utime_usec, stime_sec, stime_usec;
421 // long long ru_maxrss, ru_majflt, ru_nswap, ru_inblock, ru_oublock;
422 // long long ru_msgsnd, ru_msgrcv, ru_nsignals;
423 
424 // Check if actual length wanted
425 //
426  if (!bfr) return sizeof(statfmt)+16*13;
427 
428 // Get the statistics
429 //
430  if (getrusage(RUSAGE_SELF, &r_usage)) return 0;
431 
432 // Convert fields to correspond to the format we are using. Commented out fields
433 // are either not uniformaly reported or are incorrectly reported making them
434 // useless across multiple platforms.
435 //
436 //
437  utime_sec = static_cast<long long>(r_usage.ru_utime.tv_sec);
438  utime_usec = static_cast<long long>(r_usage.ru_utime.tv_usec);
439  stime_sec = static_cast<long long>(r_usage.ru_stime.tv_sec);
440  stime_usec = static_cast<long long>(r_usage.ru_stime.tv_usec);
441 // ru_maxrss = static_cast<long long>(r_usage.ru_maxrss);
442 // ru_majflt = static_cast<long long>(r_usage.ru_majflt);
443 // ru_nswap = static_cast<long long>(r_usage.ru_nswap);
444 // ru_inblock = static_cast<long long>(r_usage.ru_inblock);
445 // ru_oublock = static_cast<long long>(r_usage.ru_oublock);
446 // ru_msgsnd = static_cast<long long>(r_usage.ru_msgsnd);
447 // ru_msgrcv = static_cast<long long>(r_usage.ru_msgrcv);
448 // ru_nsignals = static_cast<long long>(r_usage.ru_nsignals);
449 
450 // Format the statistics
451 //
452  return snprintf(bfr, bln, statfmt,
453  utime_sec, utime_usec, stime_sec, stime_usec
454 // ru_maxrss, ru_majflt, ru_nswap, ru_inblock, ru_oublock,
455 // ru_msgsnd, ru_msgrcv, ru_nsignals
456  );
457 }
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:221
void Reset()
Definition: XrdSysTimer.hh:61
unsigned long Report(double &)
Definition: XrdSysTimer.cc:100
XrdOucEnv theEnv
XrdBuffManager BuffPool
Definition: XrdGlobals.cc:51