otsdaq_utilities  v2_02_00
ConsoleSupervisor.h
1 #ifndef _ots_ConsoleSupervisor_h_
2 #define _ots_ConsoleSupervisor_h_
3 
4 
5 #include "otsdaq-core/CoreSupervisors/CoreSupervisorBase.h"
6 
7 #include <mutex> //for std::mutex
8 
9 
10 namespace ots
11 {
12 
13 //ConsoleSupervisor
14 // This class handles the presentation of Message Facility printouts to the web desktop Console
15 class ConsoleSupervisor : public CoreSupervisorBase
16 {
17 
18 public:
19 
20 
21 public:
22 
23  XDAQ_INSTANTIATOR();
24 
25  ConsoleSupervisor (xdaq::ApplicationStub* s);
26  virtual ~ConsoleSupervisor (void);
27 
28  void init (void);
29  void destroy (void);
30 
31  virtual void defaultPage (xgi::Input* in, xgi::Output* out) override;
32  virtual void request (const std::string& requestType, cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut, const WebUsers::RequestUserInfo& userInfo) override;
33 
34  virtual void forceSupervisorPropertyValues (void) override; //override to force supervisor property values (and ignore user settings)
35 
36 
37 private:
38 
39  static void messageFacilityReceiverWorkLoop (ConsoleSupervisor *cs);
40  void insertMessageRefresh (HttpXmlDocument *xmldoc, const clock_t lastUpdateClock, const unsigned int lastUpdateIndex);
41 
42 
43  // UDP Message Format:
44  // UDPMFMESSAGE|TIMESTAMP|SEQNUM|HOSTNAME|HOSTADDR|SEVERITY|CATEGORY|APPLICATION|PID|ITERATION|MODULE|(FILE|LINE)|MESSAGE
45  // FILE and LINE are only printed for s67+
46  struct ConsoleMessageStruct
47  {
48  ConsoleMessageStruct()
49  {
50  buffer.resize(BUFFER_SZ);
51  timeStamp = 0; //use this being 0 to indicate uninitialized
52  countStamp = (time_t)-1; //this is still a valid countStamp, just unlikely to be reached
53 
54  //init fields to position -1 (for unknown)
55  //NOTE: must be in order of appearance in buffer
56  fields[SEQID].set("SequenceID", 2, -1);
57  fields[LEVEL].set("Level", 5, -1);
58  fields[LABEL].set("Label", 6, -1);
59  fields[SOURCEID].set("SourceID", 7, -1); //number
60  fields[SOURCE].set("Source", 9, -1);
61  fields[MSG].set("Msg", 10, -1); //the message facility contents have changed!
62 //#if MESSAGEFACILITY_HEX_VERSION >= 0x20201
63 // fields[MSG].set("Msg", 13, -1);
64 //#else
65 // fields[MSG].set("Msg", 11, -1);
66 //#endif
67  }
68 
69  void set(const std::string &msg, const time_t count)
70  {
71  buffer = (std::string)(msg.substr(0, BUFFER_SZ)); //clip to BUFFER_SZ
72 
73  timeStamp = time(0); //get time of msg
74  countStamp = count; //get "unique" incrementing id for message
75 
76  //find fields
77  int i = 0, m = 0;
78  size_t p = 0;
79 
80  //if first field is position 0, mark it complete
81  if (fields[i].markerCount == 0)
82  fields[i++].posInString = 0;
83 
84  //loop until no more markers
85  while ((p = buffer.find('|', p)) != std::string::npos)
86  {
87  ++m; //found next marker
88 
89  if (i < (int)fields.size() &&
90  m == fields[i].markerCount) //found marker for field
91  fields[i++].posInString = p + 1; //set position in string and move on to next field
92 
93  //change all | to \0 so strings are terminated
94  buffer[p] = '\0';
95 
96  //handle special Level/Label case (where | is missing)
97  if(i == LABEL && p + 1 + strlen(&buffer[p+1]) != msg.length())
98  {
99  //std::cout << "LEN = " << strlen(&buffer[p+1]) << __E__;
100  //std::cout << "buff = " <<(&buffer[p+1]) << __E__;
101  fields[i++].posInString = p + 2 + strlen(&buffer[p+1]);
102  }
103  }
104 
105  //debug
106  // std::cout << ":::::" << msg << "\n";
107  // for(auto &f: fields)
108  // {
109  // std::cout << f.fieldName << ": ";
110  // std::cout << (char *)&buffer[f.posInString] << std::endl;
111  // }
112  }
113 
114  const char * getMsg() { return (char *)&buffer[fields[MSG].posInString]; }
115  const char * getLabel() { return (char *)&buffer[fields[LABEL].posInString]; }
116  const char * getLevel() { return (char *)&buffer[fields[LEVEL].posInString]; }
117  const char * getSourceID() { return (char *)&buffer[fields[SOURCEID].posInString]; }
118  const long long getSourceIDAsNumber()
119  {
120  //signed to allow -1 to ignore sequence number
121  long long srcid;
122  sscanf((char *)&buffer[fields[SOURCEID].posInString], "%lld", &srcid); //signed long long
123  return srcid;
124  }
125  const char * getSource() { return (char *)&buffer[fields[SOURCE].posInString]; }
126  const char * getSequenceID() { return (char *)&buffer[fields[SEQID].posInString]; }
127  const unsigned int getSequenceIDAsNumber()
128  {
129  unsigned long long longSeqid;
130  sscanf((char *)&buffer[fields[SEQID].posInString], "%llu", &longSeqid); //unsigned long long
131  //Eric says this field is a "C++ int" which can change based on OS from 32 to 64?...
132  //then convert to unsigned int for our sanity
133  return (unsigned int)longSeqid;
134  }
135 
136  const char * getField(int i) { return (char *)&buffer[fields[i].posInString]; }
137  const time_t getTime() { return timeStamp; }
138  const time_t getCount() { return countStamp; }
139 
140 
141 
142  //define field structure
143  struct FieldStruct
144  {
145  void set(const std::string &fn, const int mc, const int ps)
146  {
147  fieldName = fn; markerCount = mc; posInString = ps;
148  }
149 
150  std::string fieldName;
151  int markerCount;
152  int posInString;
153  };
154 
155  //define field index enum alias
156  enum
157  { //must be in order of appearance in buffer
158  SEQID,
159  LEVEL, //aka SEVERITY
160  LABEL,
161  SOURCEID,
162  SOURCE,
163  MSG,
164  };
165 
166  const int BUFFER_SZ = 5000;
167  std::array<FieldStruct, 6> fields;
168  private:
169  std::string buffer;
170  time_t timeStamp;
171  time_t countStamp;
172  };
173 
174  std::array<ConsoleMessageStruct, 100> messages_;
175  std::mutex messageMutex_;
176  volatile unsigned int writePointer_; //use volatile to avoid compiler optimizations
177  time_t messageCount_; //"unique" incrementing ID for messages
178 
179  //members for the refresh handler, ConsoleSupervisor::insertMessageRefresh
180  unsigned int refreshReadPointer_;
181  char refreshTempStr_[50];
182  unsigned int refreshIndex_;
183  xercesc::DOMElement* refreshParent_;
184  time_t refreshCurrentLastCount_;
185 };
186 
187 
188 }
189 
190 #endif