Residue C++ Client
Official C++ client library to interact with residue seamlessly.
residue.h
1 //
2 // residue.h
3 //
4 // Official C++ client library for Residue logging server
5 //
6 // Copyright (C) 2017-present Muflihun Labs
7 // Copyright (C) 2017-present @abumusamq
8 //
9 // https://muflihun.com/
10 // https://muflihun.github.io/residue/
11 // https://github.com/muflihun/residue-cpp/
12 //
13 // See https://github.com/muflihun/residue-cpp/blob/master/LICENSE
14 // for licensing information
15 //
16 
17 #ifndef Residue_h
18 #define Residue_h
19 
20 #include <cstdint>
21 #include <ctime>
22 #include <atomic>
23 #include <deque>
24 #include <exception>
25 #include <mutex>
26 #include <thread>
27 #include <tuple>
28 #include <unordered_map>
29 #include "easylogging++.h"
30 
31 class ResidueDispatcher;
32 
36 class ResidueException : public std::runtime_error
37 {
38 public:
42  explicit ResidueException(const std::string& msg) : runtime_error(msg) {}
43  virtual ~ResidueException() = default;
44 };
45 
49 void residueCrashHandler(int) noexcept;
50 
55 class Residue {
56 public:
60  enum Flag : unsigned int {
61  NONE = 0,
62  ALLOW_UNKNOWN_LOGGERS = 1,
63  ALLOW_BULK_LOG_REQUEST = 16,
64  COMPRESSION = 256,
65  };
66 
67  enum class InternalLoggingLevel : std::int8_t {
68  crazy = 0,
69  debug = 1,
70  info = 2,
71  warning = 3,
72  error = 4,
73  none = 5
74  };
75 
76 #ifdef RESIDUE_PROFILING
77  unsigned long queue_ms;
78  unsigned long dispatch_ms;
79  int c_total;
80  int c_dispatched;
81 #endif
82 
87  static const std::size_t DEFAULT_KEY_SIZE;
88 
92  static const int DEFAULT_PORT;
93 
97  static const std::string LOCALHOST;
98 
103  static const unsigned int TOUCH_THRESHOLD;
104 
108  static volatile int s_internalLoggingLevel;
109 
113  static inline Residue& instance() noexcept
114  {
115  static Residue s_instance;
116  return s_instance;
117  }
118 
119  virtual ~Residue() noexcept;
120 
121  Residue(Residue&&) = delete;
122  Residue(const Residue&) = delete;
123  Residue& operator=(const Residue&) = delete;
124 
128  static std::string version() noexcept;
129 
133  static std::string info() noexcept;
134 
141  static inline void connect(const std::string& host, int port)
142  {
143  Residue::instance().connect_(host, port);
144  }
145 
151  static inline void connect(int port)
152  {
153  Residue::instance().connect_(Residue::LOCALHOST, port);
154  }
155 
161  static inline void connect(const std::string& host)
162  {
163  Residue::instance().connect_(host, Residue::DEFAULT_PORT);
164  }
165 
173  static inline void connect()
174  {
176  }
177 
183  static inline void reconnect(const std::string& host = "", int port = -1)
184  {
186  Residue::connect(host.empty() ? Residue::instance().m_host : host,
187  port == -1 ? Residue::instance().m_port : port);
188  }
189 
194  static inline bool connected() noexcept
195  {
196  return Residue::instance().m_connected;
197  }
198 
202  static inline const std::string& clientId() noexcept
203  {
204  return Residue::instance().m_clientId;
205  }
206 
211  static inline bool connecting() noexcept
212  {
213  return Residue::instance().m_connecting;
214  }
215 
220  static inline unsigned int maxBulkSize() noexcept
221  {
222  return Residue::instance().m_maxBulkSize;
223  }
224 
228  static inline unsigned int serverFlags() noexcept
229  {
230  return Residue::instance().m_serverFlags;
231  }
232 
238  static void disconnect() noexcept;
239 
243  static inline void wait() noexcept
244  {
245  if (Residue::instance().m_dispatcher->joinable()) {
246  Residue::instance().m_dispatcher->join();
247  }
248  }
249 
253  static inline void setApplicationId(const std::string& id) noexcept
254  {
255  Residue::instance().m_applicationId = id;
256  }
257 
261  static inline void setResidueHomePath(const std::string& path) noexcept
262  {
263  Residue::instance().m_homepath = path;
264  }
265 
271  static inline void enableBulkDispatch()
272  {
273  if (connected() && !hasFlag(Flag::ALLOW_BULK_LOG_REQUEST)) {
274  throw std::invalid_argument("Bulk log requests not allowed by this server");
275  }
276  Residue::instance().m_bulkDispatch = true;
277  }
278 
282  static inline void disableBulkDispatch() noexcept
283  {
284  Residue::instance().m_bulkDispatch = false;
285  }
286 
290  static inline void enableUtc() noexcept
291  {
292  Residue::instance().m_utc = true;
293  }
294 
298  static inline void disableUtc() noexcept
299  {
300  Residue::instance().m_utc = false;
301  }
302 
306  static inline void setTimeOffset(int offset) noexcept
307  {
308  Residue::instance().m_timeOffset = offset;
309  }
310 
328  static inline void setDispatchDelay(unsigned int delay) noexcept
329  {
330  Residue::instance().m_dispatchDelay = delay;
331  }
332 
339  static inline void setBulkSize(unsigned int bulkSize)
340  {
341  if (connected() && bulkSize > maxBulkSize()) {
342  throw ResidueException("Invalid bulk dispatch size. Maximum allowed: " + std::to_string(maxBulkSize()));
343  }
344  Residue::instance().m_bulkSize = bulkSize;
345  }
346 
355  static inline void enableAutoBulkParams() noexcept
356  {
357  Residue::instance().m_autoBulkParams = true;
358  }
359 
366  static inline void disableAutoBulkParams() noexcept
367  {
368  Residue::instance().m_autoBulkParams = false;
369  }
370 
386  static inline void setKeySize(std::size_t keySize)
387  {
388  if (keySize != 2048 && keySize != 2048 * 2 && keySize != 2048 * 4) {
389  throw ResidueException("Invalid key size. Please select 2048, 4096 or 8192");
390  }
391  Residue::instance().m_keySize = keySize;
392  }
393 
397  static inline void setApplicationArgs(int argc, char** argv)
398  {
399  START_EASYLOGGINGPP(argc, argv);
400  }
401 
407  static inline void setApplicationArgs(int argc, const char** argv)
408  {
409  START_EASYLOGGINGPP(argc, argv);
410  }
411 
420  static inline void setKnownClient(const std::string& clientId, const std::string& privateKeyPem)
421  {
422  Residue::instance().m_clientId = clientId;
423  Residue::instance().m_rsaPrivateKey = privateKeyPem;
424  if (!clientId.empty() && privateKeyPem.empty()) {
425  throw ResidueException("Please provide private key for known client.");
426  }
427  Residue::instance().m_knownClient = !clientId.empty() && !privateKeyPem.empty();
428  }
429 
434  static inline void setServerPublicKey(const std::string& publicKeyPem)
435  {
436  Residue::instance().m_serverPublicKey = publicKeyPem;
437  }
438 
446  static inline void setInternalLoggingLevel(int level)
447  {
449  }
450 
455  static inline void setInternalLoggingLevel(InternalLoggingLevel level)
456  {
457  setInternalLoggingLevel(static_cast<int>(level));
458  }
459 
463  static inline bool hasFlag(Flag flag) noexcept
464  {
465  return serverFlags() != 0 && (serverFlags() & flag) != 0;
466  }
467 
471  static inline void setThreadName(const std::string& threadName) noexcept
472  {
473  el::Helpers::setThreadName(threadName);
474  }
475 
480  static inline void enableCrashHandler(const std::string& loggerId = el::base::consts::kDefaultLoggerId)
481  {
482 #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
483  Residue::instance().m_crashHandlerLoggerId = loggerId;
484  el::Helpers::setCrashHandler(residueCrashHandler);
485 #endif
486  }
487 
493  static inline const std::vector<std::string>& errors() noexcept
494  {
495  return Residue::instance().m_errors;
496  }
497 
520  static void loadConfiguration(const std::string& jsonFilename);
521 
527  static inline void loadConfigurationFromJson(const std::string& json)
528  {
529  Residue::instance().loadConfigurationFromJson_(json);
530  }
531 
536  static inline void saveConnection(const std::string& outputFile)
537  {
538  Residue::instance().saveConnection_(outputFile);
539  }
540 
541  static inline std::string connection()
542  {
543  return Residue::instance().m_connection;
544  }
545 
559  static inline void loadConnection(const std::string& connectionFile)
560  {
561  Residue::instance().loadConnection_(connectionFile);
562  }
563 
571  static void loadConnectionFromJson(const std::string& connectionJson);
572 
576  inline std::string crashHandlerLoggerId() const noexcept
577  {
578  return m_crashHandlerLoggerId;
579  }
580 
585  unsigned long getTimestamp() const noexcept
586  {
587  std::time_t seconds;
588  std::time(&seconds);
589  return seconds;
590  }
591 
592  inline std::string serverVersion() const noexcept
593  {
594  return m_serverVersion;
595  }
596 
597 private:
598 
599  // defs and structs
600  struct RawRequest {
601  unsigned long date;
602  std::string threadId;
603  std::string loggerId;
604  el::base::type::string_t msg;
605  std::string file;
606  el::base::type::LineNumber line;
607  std::string func;
608  unsigned int level;
609  el::base::type::VerboseLevel vlevel;
610  };
611 
612  // private members
613 
614  std::string m_host;
615  int m_port;
616 
617  std::string m_connection;
618 
619  std::atomic<bool> m_connected;
620  std::atomic<bool> m_connecting;
621  std::atomic<bool> m_disconnected; // user called disconnect()
622 
623  std::atomic<bool> m_bulkDispatch;
624  unsigned int m_bulkSize;
625  unsigned int m_maxBulkSize;
626 
627  std::string m_rsaPrivateKey;
628  std::string m_rsaPrivateKeySecret;
629  std::string m_rsaPublicKey;
630  std::size_t m_keySize;
631  std::string m_clientId;
632  std::string m_key;
633  std::string m_serverVersion;
634  std::string m_serverPublicKey;
635  unsigned int m_age;
636  unsigned long m_dateCreated;
637  int m_loggingPort;
638  unsigned int m_serverFlags;
639  std::atomic<bool> m_utc;
640  std::atomic<int> m_timeOffset;
641  std::atomic<unsigned int> m_dispatchDelay;
642 
643  std::deque<RawRequest> m_requests;
644 
645  std::recursive_mutex m_mutex;
646  std::thread* m_dispatcher;
647  std::atomic<bool> m_running;
648  std::atomic<bool> m_autoBulkParams;
649 
650  std::string m_applicationId;
651  bool m_knownClient;
652 
653  std::string m_homepath;
654 
655  std::string m_crashHandlerLoggerId;
656 
657  std::vector<std::string> m_errors;
658  std::mutex m_errorsMutex;
659 
660  friend class ResidueDispatcher;
661 
662  Residue() noexcept;
663 
664  // client
665  bool isClientValid() const noexcept;
666  bool shouldTouch() const noexcept;
667  void touch() noexcept;
668  void healthCheck() noexcept;
669 
670  // connect
671  void connect_(const std::string& host, int port, bool estabilishFullConnection = true);
672  void disconnect_() noexcept;
673  void reset();
674  void onConnect() noexcept;
675  void loadConnectionFromJson_(const std::string& connectionJson);
676  void saveConnection_(const std::string& outputFile);
677  void loadConnection_(const std::string& connectionFile);
678 
679  void loadConfigurationFromJson_(const std::string& json);
680 
681  // request
682  void addToQueue(RawRequest&&) noexcept;
683  void dispatch();
684  std::string requestToJson(RawRequest&& request);
685 
686  void addError(const std::string& errorText) noexcept;
687 
688  std::string& resolveResidueHomeEnvVar(std::string& str);
689 };
690 
691 #endif /* Residue_h */
static void loadConfigurationFromJson(const std::string &json)
Loads configuration from JSON.
Definition: residue.h:527
static const std::string LOCALHOST
127.0.0.1
Definition: residue.h:97
static void setKeySize(std::size_t keySize)
Size of RSA key (in bits) when connecting.
Definition: residue.h:386
static void setBulkSize(unsigned int bulkSize)
Sets number of log messages to be bulked together.
Definition: residue.h:339
static void connect(int port)
Connect to residue on localhost.
Definition: residue.h:151
static void setApplicationArgs(int argc, const char **argv)
Wrapper for START_EASYLOGGINGPP.
Definition: residue.h:407
Exception thrown by all the residue helper and internal methods.
Definition: residue.h:36
static bool connecting() noexcept
Check connection to the server.
Definition: residue.h:211
static const std::size_t DEFAULT_KEY_SIZE
Default key size for RSA.
Definition: residue.h:87
static void setApplicationArgs(int argc, char **argv)
Definition: residue.h:397
static unsigned int serverFlags() noexcept
If connected this identifies server flags.
Definition: residue.h:228
static const int DEFAULT_PORT
Default port 8777 of residue.
Definition: residue.h:92
static const unsigned int TOUCH_THRESHOLD
Threshold (seconds) to check against client age and whether we should send touch request or not...
Definition: residue.h:103
static void setResidueHomePath(const std::string &path) noexcept
Sets residue home path for $RESIDUE_HOME.
Definition: residue.h:261
static void enableAutoBulkParams() noexcept
Enables automatic setting of bulk parameters depending on what&#39;s most efficient. It essentially enabl...
Definition: residue.h:355
static void setKnownClient(const std::string &clientId, const std::string &privateKeyPem)
If server knows you already you can let us know and we will use this identity.
Definition: residue.h:420
static void loadConnection(const std::string &connectionFile)
Loads connection from file instead of re-pulling it from server.
Definition: residue.h:559
The Residue class provides helper methods to connect and interact to residue server seamlessly...
Definition: residue.h:55
static void enableCrashHandler(const std::string &loggerId=el::base::consts::kDefaultLoggerId)
Enables crash handler.
Definition: residue.h:480
static void connect()
Connect to residue on localhost using default port. This is more useful when you have client ID so yo...
Definition: residue.h:173
std::string crashHandlerLoggerId() const noexcept
Crash handler logger. Not for public use.
Definition: residue.h:576
unsigned long getTimestamp() const noexcept
Gets timestamp for replay attack prevention. This function always uses unix-time for comparison...
Definition: residue.h:585
static void setApplicationId(const std::string &id) noexcept
Application ID is what gets passed on to the server for app format specifier.
Definition: residue.h:253
Flag
Server flags enum that are relavant to the client.
Definition: residue.h:60
static std::string info() noexcept
Version of Residue library and dependencies.
static void disableBulkDispatch() noexcept
disableBulkDispatch turns off bulk dispatch.
Definition: residue.h:282
static void loadConnectionFromJson(const std::string &connectionJson)
Loads configuration from JSON.
static void disconnect() noexcept
Safely disconnects from the server. This will also call wait()
static void setInternalLoggingLevel(InternalLoggingLevel level)
Helper function to set logging level for debugging/info.
Definition: residue.h:455
static void connect(const std::string &host)
Connect to residue using default port.
Definition: residue.h:161
ResidueException(const std::string &msg)
Main constructor.
Definition: residue.h:42
static void setInternalLoggingLevel(int level)
Sets logging level for residue client library internal logging.
Definition: residue.h:446
static void setServerPublicKey(const std::string &publicKeyPem)
Sets server public key for encrypted connection.
Definition: residue.h:434
static const std::vector< std::string > & errors() noexcept
Useful for debugging the issue. Contains last 10 errors from server (i.e, error_text in response) Las...
Definition: residue.h:493
static void setTimeOffset(int offset) noexcept
Offset in seconds for log time. [Default: 0].
Definition: residue.h:306
static std::string version() noexcept
Version of Residue library.
static unsigned int maxBulkSize() noexcept
If connected this identifies maximum number of items in bulk that server accepts. ...
Definition: residue.h:220
static void enableUtc() noexcept
Send UTC time to the server. By default local time is sent.
Definition: residue.h:290
static void disableAutoBulkParams() noexcept
Disables automatic setting of bulk params.
Definition: residue.h:366
static void wait() noexcept
Wait to dispatch all the log requests to the server.
Definition: residue.h:243
static void setDispatchDelay(unsigned int delay) noexcept
Delay between dispatching log messages (in milliseconds) [Default: 1ms].
Definition: residue.h:328
static volatile int s_internalLoggingLevel
See setInternalLoggingLevel(InternalLoggingLevel)
Definition: residue.h:108
static void disableUtc() noexcept
Send Local time to the server. By default local time is sent.
Definition: residue.h:298
static const std::string & clientId() noexcept
Returns current client ID. Returns empty if not connected.
Definition: residue.h:202
static void loadConfiguration(const std::string &jsonFilename)
Loads all the configurations from JSON file.
static void enableBulkDispatch()
enableBulkDispatch turns on bulk dispatch.
Definition: residue.h:271
static void reconnect(const std::string &host="", int port=-1)
Reconnects residue server using new or initially provided parameters. (Disconnect then connect) ...
Definition: residue.h:183
static bool hasFlag(Flag flag) noexcept
Checks for server flag and returns true if flag set otherwise not.
Definition: residue.h:463
static Residue & instance() noexcept
Singleton instance.
Definition: residue.h:113
static bool connected() noexcept
Check connection to the server.
Definition: residue.h:194
static void saveConnection(const std::string &outputFile)
Saves connection parameter to the file.
Definition: residue.h:536
static void setThreadName(const std::string &threadName) noexcept
Sets current thread name.
Definition: residue.h:471