File: Snoop.hh

package info (click to toggle)
cadabra2 2.4.3.2-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 78,732 kB
  • sloc: ansic: 133,450; cpp: 92,064; python: 1,530; javascript: 203; sh: 184; xml: 182; objc: 53; makefile: 51
file content (347 lines) | stat: -rw-r--r-- 11,063 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

/*

   Snoop
   Copyright (C) 2015-2020  Kasper Peeters
   Available under the terms of the GPL v3.

   Snoop is a lightweight logging library which stores its log entries in
	a local SQLite database or on a remote server.

 */

#pragma once

#include <string>
#include <sstream>
#include <sqlite3.h>
#include <stdint.h>
#include <mutex>
#include "nlohmann/json.hpp"
#include <thread>
#include <set>
#ifdef SNOOP_SSL
  #include <websocketpp/config/asio_client.hpp>
#else
  #include <websocketpp/config/asio_no_tls_client.hpp>
#endif
#include <websocketpp/client.hpp>
#include <websocketpp/common/thread.hpp>
#include <websocketpp/common/functional.hpp>

#ifndef _MSC_VER
  #include <unistd.h>
#endif

#ifdef SNOOP_SSL
   typedef websocketpp::client<websocketpp::config::asio_tls_client> WebsocketClient;
#else
   typedef websocketpp::client<websocketpp::config::asio_client> WebsocketClient;
#endif
typedef websocketpp::config::asio_client::message_type::ptr   message_ptr;

std::string safestring(const unsigned char *c);

namespace snoop {

	class SnoopImpl;
   class Flush {};
   extern Flush flush;

	/// Logging class with functionality to send log information to a
	/// remote server using a websocket connection.

   class Snoop {
      public:
         Snoop();
         ~Snoop();

			/// Initialise the logging stream. Should be called once at
         /// program startup, but can be called multiple times without
         /// causing problems.

			void init(const std::string& app_name, const std::string& app_version, 
                      std::string server="", std::string local_log_file="", std::string machine_id="");

			/// Get a string which uniquely identifies the current user. This is
			/// stored in ~/.config/snoop/appname.conf, and in the 'user_id' field
			/// in each LogEntry. Note that this is different from the 'uuid' field,
			/// which will change from one run to the next.

			std::string get_user_uuid(const std::string& app_name);

			/// Operator to initialise a logging entry with the type of
			/// the log message as well as (optionally) the file, line
			/// number and method.

			Snoop& operator()(const std::string& type="", std::string fl="", int loc=-1, std::string method="");

         /// Determine the 'type' field of records which should not be
         /// sent to the remote logging server. Can be called multiple times.

         void set_local_type(const std::string& type);

         /// Generic operator to log an object to the log message being constructed.

			template<class T>
			Snoop& operator<<(const T& obj) {
			   out_ <<(obj);
			   return *this;
			}

			/// Log payload data.

			Snoop& payload(const std::vector<char>&);
			
			/// Flush the log entry to disk/server.

         Snoop& operator<<(const Flush&);

			/// Set to sync with server after every log line.

			void set_sync_immediately(bool);

			/// Ensure that the local database is synchronised with the
			/// server (this sends multiple app or log entries in one
			/// websocket message). Leave the bool argument at its
			/// default argument under all normal circumstances.

			void sync_with_server(bool from_wsthread=false);
			
			/// As above, but only for run entries. 

			void sync_runs_with_server(bool from_wsthread=false);
			
			/// As above, but only for log entries. 

			void sync_logs_with_server(bool from_wsthread=false);
			
			/// As above, but only for payload data. 

			void sync_payloads_with_server(bool from_wsthread=false);

         /// Are we connected to the log server?

         bool is_connected() const;         

         /// Return version of last run seen on given device.
         
         std::string last_seen_version(std::string machine_id);

         /// Authentication logic; passes ticket or credentials
         /// to server, and registers callback function for when
         /// the response comes back.

         bool authenticate(std::function<void (std::string, bool)>, std::string user="", std::string pass="");
       
         /// Get status of a given authentication ticket.

			class Ticket {
				public:
					Ticket();
					int         ticket_id;
					int         user_id;
					std::string ticket_uuid;
					bool        valid;
			};
         Ticket is_ticket_valid(std::string ticket_uuid);

         /// C++ representation of a run entry.

			class AppEntry {
				public:
					AppEntry();
					AppEntry(const std::string& uuid_, uint64_t create_millis_, uint64_t receive_millis_, uint64_t pid_, 
								const std::string& ip_address_, const std::string& machine_id_, 
								const std::string& app_name_,   const std::string& app_version_,
								const std::string& user_id_,
								int server_status_, int create_timezone);

					std::string to_json(bool human_readable) const;
					void        from_json(const nlohmann::json&);

					int         id;
					std::string uuid;
					uint64_t    create_millis;
					uint64_t    receive_millis;
					uint64_t    pid;
					std::string ip_address;
					std::string machine_id;
					std::string app_name;
					std::string app_version;
					std::string user_id;
					int         server_status; // 1: synced, 0 and negative: number of attempts at syncing made
					bool        connected;
					int         create_timezone;					
			};

			/// C++ representation of a log entry.

			class LogEntry {
				public:
					LogEntry();
					LogEntry(int log_id_, int client_log_id_, int id_, const std::string&, 
								uint64_t, uint64_t, const std::string&, int, const std::string&, 
								const std::string& , const std::string&, int status, const std::string&,
								int create_timezone);

					std::string to_json(bool human_readable) const;
					void        from_json(const nlohmann::json&);
					
					int         log_id;
					int         client_log_id;
					int         id;
					std::string uuid;              // this goes on the wire, but is not stored on disk.
					uint64_t    create_millis;
					uint64_t    receive_millis;
					std::string loc_file;
					int         loc_line;
					std::string loc_method;
					std::string type;
					std::string message;
					int         server_status;     // 1: synced, 0 and negative: number of attempts at syncing made
					std::string session_uuid;
					int         create_timezone;
			};

			/// C++ representation of a payload entry.

			class PayLoad {
				public:
					PayLoad();
					PayLoad(const std::vector<char>& data);

					std::string to_json(bool human_readable) const;
					void        from_json(const nlohmann::json&);

					int         payload_id;
					int         client_payload_id;
					int         id;
					std::string uuid;              // this goes on the wire, but is not stored on disk.
					uint64_t    create_millis;
					uint64_t    receive_millis;
					std::string payload;
					int         server_status;     // 1: synced, 0 and negative: number of attempts at syncing made
					int         create_timezone;
			};
       
          /// Client-side fetching of ticket.
       
          std::string get_local_ticket();
       

      protected:
			/// Start the websocket client. This tries to connect to the server and then
         /// waits in a separate thread until the server sends us something (typically
         /// in response to something the main thread makes by calling wsclient.send).

			void start_websocket_client();

			/// Ensure that the required tables are present in the
			/// database file.

			void create_tables();

	      /// Ensure that the required authentication tables are present
	      /// in the authentication database. Only used on the server.

	      void create_authentication_tables();

			/// Obtain a uuid by finding the last AppEntry stored in the
			/// local database. Will attempt to re-turn a previously
			/// generated uuid but will do so only if one is stored for
			/// the current pid; if no entry with the current pid is
			/// stored then a new one will always be generated.

			void obtain_uuid();

			/// Store an app entry in the database. Will update the 'id'
			/// field in the AppEntry.

			bool store_app_entry(Snoop::AppEntry&);
			bool store_app_entry_without_lock(Snoop::AppEntry&);

			/// Store a log entry in the local database. Generates its
			/// own receive_millis field (the one given gets
			/// overwritten). Will update the 'id' field in the LogEntry.
			/// Returns 'true' if the entry was stored, or 'false' if an
			/// entry with this client_log_id was already present (except
			/// when it is 0).

			bool store_log_entry(Snoop::LogEntry&, bool avoid_server_duplicates);

			/// Store payload data in the local database.

			bool store_payload_entry(Snoop::PayLoad&);

			/// Store an attempt to login into the authentication database.
			
			bool store_auth_attempt_entry(int user_id, int ticket_id, int valid, std::string msg);
			
			/// Return a vector of all aps registered in the database. If
			/// the uuid filter is non-empty, will filter on the given
			/// uuid.

			std::vector<Snoop::AppEntry> get_app_registrations(std::string uuid_filter="");

         /// Store an authentication ticket in the database.
         
	      int store_ticket(std::string ticket_uuid, int user_id, bool valid);

         /// Client-side storing of ticket (simpler than store_ticket above).
         /// If ticket is empty, only deletes current ticket.

         void set_local_ticket(std::string ticket_uuid);
         
         /// Variables
         
         bool          sync_immediately_;
	      sqlite3      *db, *payload_db, *auth_db;
			sqlite3_stmt *insert_statement, *id_for_uuid_statement, *payload_insert_statement;
			std::recursive_mutex    sqlite_mutex;

      private:
			/// Websocket client to talk to a remote logging server.
			
			WebsocketClient                 wsclient;
			std::thread                     wsclient_thread;
			std::mutex                      connection_mutex;
			std::condition_variable         connection_cv;
			bool                            connection_is_open, connection_attempt_failed;
			WebsocketClient::connection_ptr connection;
			websocketpp::connection_hdl     our_connection_hdl;
			
			void on_client_open(websocketpp::connection_hdl hdl);
			void on_client_fail(websocketpp::connection_hdl hdl);
			void on_client_close(websocketpp::connection_hdl hdl);
			void on_client_message(websocketpp::connection_hdl hdl, message_ptr msg);

			std::ostringstream out_;
			
			Snoop::AppEntry    this_app_;
			Snoop::LogEntry    this_log_;
			std::string        server_;

         std::recursive_mutex   call_mutex;
			bool         secure;

	      std::set<std::string> local_types;
//	      std::set<std::string> ...
         std::function<void (std::string, bool)> authentication_callback;

   };

	extern Snoop log;

	const char info[] ="info";
	const char warn[] ="warning";
	const char error[]="error";
	const char fatal[]="fatal";
	const char email[]="email";
}

// set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst
//  ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")

#define LOC __FILE__, __LINE__, __func__