Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
PersistedEventLog.cs
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Threading;
5using System.Threading.Tasks;
9
11{
17 {
18 private Timer timer;
19 private int eventLifetimeDays;
20 private string defaultFacility;
21 private string defaultFacilityDigest = null;
22
29 : this(EventLifetimeDays, null, string.Empty, string.Empty)
30 {
31 }
32
39 public PersistedEventLog(int EventLifetimeDays, TimeSpan? CleanupTime)
40 : this(EventLifetimeDays, CleanupTime, string.Empty, string.Empty)
41 {
42 }
43
52 public PersistedEventLog(int EventLifetimeDays, TimeSpan? CleanupTime, string DefaultFacility, string DefaultFacilityKey)
53 : base("Persisted Event Log")
54 {
55 if (EventLifetimeDays <= 0)
56 throw new ArgumentOutOfRangeException("The lifetime must be a positive number of days.", nameof(EventLifetimeDays));
57
58 this.eventLifetimeDays = EventLifetimeDays;
59 this.defaultFacility = DefaultFacility;
60 this.defaultFacilityDigest = this.ComputeDigest(DefaultFacilityKey);
61
62 if (CleanupTime.HasValue)
63 this.TurnOnDailyPurge(EventLifetimeDays, CleanupTime.Value);
64 else
65 this.timer = null;
66 }
67
73 public void TurnOnDailyPurge(int EventLifetimeDays, TimeSpan CleanupTime)
74 {
75 this.TurnOffDailyPurge();
76
77 if (CleanupTime < TimeSpan.Zero || CleanupTime.TotalDays >= 1.0)
78 throw new ArgumentOutOfRangeException("Invalid time.", nameof(CleanupTime));
79
80 int MillisecondsPerDay = 1000 * 60 * 60 * 24;
81 int MsUntilNext = (int)((DateTime.Today.AddDays(1).Add(CleanupTime) - DateTime.Now).TotalMilliseconds + 0.5);
82
83 this.eventLifetimeDays = EventLifetimeDays;
84 this.timer = new Timer(this.DoCleanup, null, MsUntilNext, MillisecondsPerDay);
85 }
86
91 public bool TurnOffDailyPurge()
92 {
93 if (!(this.timer is null))
94 {
95 this.timer.Dispose();
96 this.timer = null;
97
98 return true;
99 }
100 else
101 return false;
102 }
103
107 public override void Dispose()
108 {
109 this.TurnOffDailyPurge();
110 base.Dispose();
111 }
112
113 private async void DoCleanup(object P)
114 {
115 try
116 {
117 await this.DeleteOld(DateTime.Now.AddDays(-this.eventLifetimeDays));
118 }
119 catch (Exception ex)
120 {
121 Log.Exception(ex);
122 }
123 }
124
131 public Task<int> DeleteOld(DateTime Limit)
132 {
133 return DeleteOld(this.ObjectID, Limit);
134 }
135
143 public static async Task<int> DeleteOld(string ObjectId, DateTime Limit)
144 {
145 int NrEvents = 0;
146 bool Deleted;
147
148 do
149 {
150 Deleted = false;
151
152 foreach (PersistedEvent Event in await Database.FindDelete<PersistedEvent>(0, 100, new FilterFieldLesserOrEqualTo("Timestamp", Limit)))
153 {
154 NrEvents++;
155 Deleted = true;
156 }
157 }
158 while (Deleted);
159
160 if (NrEvents > 0)
161 {
162 KeyValuePair<string, object>[] Tags = new KeyValuePair<string, object>[]
163 {
164 new KeyValuePair<string, object>("Limit", Limit),
165 new KeyValuePair<string, object>("NrEvents", NrEvents)
166 };
167
168 if (NrEvents == 1)
169 Log.Informational("Deleting 1 event from the database.", ObjectId, Tags);
170 else
171 Log.Informational("Deleting " + NrEvents.ToString() + " events from the database.", ObjectId, Tags);
172 }
173
174 return NrEvents;
175 }
176
185 public Task<IEnumerable<PersistedEvent>> GetEvents(int Offset, int MaxCount, DateTime From, DateTime To)
186 {
187 return Database.Find<PersistedEvent>(Offset, MaxCount, new FilterAnd(
188 new FilterFieldGreaterOrEqualTo("Timestamp", From),
189 new FilterFieldLesserOrEqualTo("Timestamp", To)), "-Timestamp");
190 }
191
201 public Task<IEnumerable<PersistedEvent>> GetEventsOfType(int Offset, int MaxCount, EventType Type, DateTime From, DateTime To)
202 {
203 return Database.Find<PersistedEvent>(Offset, MaxCount, new FilterAnd(
204 new FilterFieldGreaterOrEqualTo("Type", Type),
205 new FilterFieldGreaterOrEqualTo("Timestamp", From),
206 new FilterFieldLesserOrEqualTo("Timestamp", To)), "-Timestamp");
207 }
208
218 public Task<IEnumerable<PersistedEvent>> GetEventsOfObject(int Offset, int MaxCount, string Object, DateTime From, DateTime To)
219 {
220 return Database.Find<PersistedEvent>(Offset, MaxCount, new FilterAnd(
221 new FilterFieldGreaterOrEqualTo("Object", Object),
222 new FilterFieldGreaterOrEqualTo("Timestamp", From),
223 new FilterFieldLesserOrEqualTo("Timestamp", To)), "-Timestamp");
224 }
225
235 public Task<IEnumerable<PersistedEvent>> GetEventsOfActor(int Offset, int MaxCount, string Actor, DateTime From, DateTime To)
236 {
237 return Database.Find<PersistedEvent>(Offset, MaxCount, new FilterAnd(
238 new FilterFieldGreaterOrEqualTo("Actor", Actor),
239 new FilterFieldGreaterOrEqualTo("Timestamp", From),
240 new FilterFieldLesserOrEqualTo("Timestamp", To)), "-Timestamp");
241 }
242
252 public Task<IEnumerable<PersistedEvent>> GetEventsOfEventId(int Offset, int MaxCount, string EventId, DateTime From, DateTime To)
253 {
254 return Database.Find<PersistedEvent>(Offset, MaxCount, new FilterAnd(
255 new FilterFieldGreaterOrEqualTo("EventId", EventId),
256 new FilterFieldGreaterOrEqualTo("Timestamp", From),
257 new FilterFieldLesserOrEqualTo("Timestamp", To)), "-Timestamp");
258 }
259
269 public Task<IEnumerable<PersistedEvent>> GetEventsOfFacility(int Offset, int MaxCount, string Facility, DateTime From, DateTime To)
270 {
271 return Database.Find<PersistedEvent>(Offset, MaxCount, new FilterAnd(
272 new FilterFieldGreaterOrEqualTo("Facility", Facility),
273 new FilterFieldGreaterOrEqualTo("Timestamp", From),
274 new FilterFieldLesserOrEqualTo("Timestamp", To)), "-Timestamp");
275 }
276
280 public int EventLifetimeDays => this.eventLifetimeDays;
281
286 public override async Task Queue(Event Event)
287 {
289
290 if (string.IsNullOrEmpty(PersistedEvent.Facility))
291 PersistedEvent.Facility = this.defaultFacility;
292
294 }
295
303 public void SetDefaultFacility(string DefaultFacility, string DefaultFacilityKey)
304 {
305 if (this.defaultFacility != DefaultFacility)
306 {
307 if (!string.IsNullOrEmpty(this.defaultFacility))
308 {
309 if (this.ComputeDigest(DefaultFacilityKey) != this.defaultFacilityDigest)
310 throw new UnauthorizedAccessException("Unauthorized to change the default facility.");
311 }
312
313 this.defaultFacility = DefaultFacility;
314 this.defaultFacilityDigest = this.ComputeDigest(DefaultFacilityKey);
315 }
316 }
317
318 private string ComputeDigest(string Key)
319 {
320 return Hashes.ComputeSHA256HashString(Encoding.UTF8.GetBytes(Key + ":" + this.defaultFacility));
321 }
322
323 internal static int ArchiveDays
324 {
325 get
326 {
327 if (registeredLog is null)
328 {
329 foreach (IEventSink Sink in Log.Sinks)
330 {
331 if (Sink is PersistedEventLog PersistedEventLog)
332 {
333 registeredLog = PersistedEventLog;
334 break;
335 }
336 }
337
338 if (registeredLog is null)
339 return 90;
340 }
341
342 return registeredLog.eventLifetimeDays;
343 }
344 }
345
346 private static PersistedEventLog registeredLog = null;
347 }
348}
Class representing an event.
Definition: Event.cs:10
Base class for event sinks.
Definition: EventSink.cs:9
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static IEventSink[] Sinks
Registered sinks.
Definition: Log.cs:122
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1647
static void Informational(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an informational event.
Definition: Log.cs:334
virtual string ObjectID
Object ID, used when logging events.
Definition: LogObject.cs:25
Class representing a persisted event.
string Facility
Facility can be either a facility in the network sense or in the system sense.
Creates an even sink that stores incoming (logged) events in the local object database,...
Task< int > DeleteOld(DateTime Limit)
Deletes old events. This method is called once a day automatically. It can also be called manually to...
Task< IEnumerable< PersistedEvent > > GetEventsOfEventId(int Offset, int MaxCount, string EventId, DateTime From, DateTime To)
Gets events relating to a specific event identity between two timepoints, ordered by descending times...
override void Dispose()
IDisposable.Dispose()
Task< IEnumerable< PersistedEvent > > GetEventsOfObject(int Offset, int MaxCount, string Object, DateTime From, DateTime To)
Gets events beloinging to a specific object between two timepoints, ordered by descending timestamp.
Task< IEnumerable< PersistedEvent > > GetEventsOfActor(int Offset, int MaxCount, string Actor, DateTime From, DateTime To)
Gets events relating to a specific actor between two timepoints, ordered by descending timestamp.
PersistedEventLog(int EventLifetimeDays, TimeSpan? CleanupTime, string DefaultFacility, string DefaultFacilityKey)
Creates an even sink that stores incoming (logged) events in the local object database,...
int EventLifetimeDays
Number of days to store events in the database.
Task< IEnumerable< PersistedEvent > > GetEventsOfType(int Offset, int MaxCount, EventType Type, DateTime From, DateTime To)
Gets events of a specific type between two timepoints, ordered by descending timestamp.
PersistedEventLog(int EventLifetimeDays, TimeSpan? CleanupTime)
Creates an even sink that stores incoming (logged) events in the local object database,...
void TurnOnDailyPurge(int EventLifetimeDays, TimeSpan CleanupTime)
Turns on the daily purge of old events.
PersistedEventLog(int EventLifetimeDays)
Creates an even sink that stores incoming (logged) events in the local object database,...
Task< IEnumerable< PersistedEvent > > GetEvents(int Offset, int MaxCount, DateTime From, DateTime To)
Gets events between two timepoints, ordered by descending timestamp.
static async Task< int > DeleteOld(string ObjectId, DateTime Limit)
Deletes old events. This method is called once a day automatically. It can also be called manually to...
Task< IEnumerable< PersistedEvent > > GetEventsOfFacility(int Offset, int MaxCount, string Facility, DateTime From, DateTime To)
Gets events relating to a specific facility between two timepoints, ordered by descending timestamp.
bool TurnOffDailyPurge()
Turns off the daily purge of old events.
override async Task Queue(Event Event)
Queues an event to be output.
void SetDefaultFacility(string DefaultFacility, string DefaultFacilityKey)
Sets the default facility. The default facility can only be reset by a caller presenting the same key...
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:19
static Task< IEnumerable< object > > FindDelete(string Collection, params string[] SortOrder)
Finds objects in a given collection and deletes them in the same atomic operation.
Definition: Database.cs:879
static async Task InsertLazy(object Object)
Inserts an object into the database, if unlocked. If locked, object will be inserted at next opportun...
Definition: Database.cs:156
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
Definition: Database.cs:247
This filter selects objects that conform to all child-filters provided.
Definition: FilterAnd.cs:10
This filter selects objects that have a named field greater or equal to a given value.
This filter selects objects that have a named field lesser or equal to a given value.
Contains methods for simple hash calculations.
Definition: Hashes.cs:59
static string ComputeSHA256HashString(byte[] Data)
Computes the SHA-256 hash of a block of binary data.
Definition: Hashes.cs:328
Interface for all event sinks.
Definition: IEventSink.cs:9
EventType
Type of event.
Definition: EventType.cs:7