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