Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
LogView.xaml.cs
1using System;
2using System.IO;
3using System.Collections.Generic;
4using System.Text;
5using System.Xml;
6using System.Xml.Schema;
7using System.Xml.Xsl;
8using System.Windows;
9using System.Windows.Controls;
10using Microsoft.Win32;
14using Waher.Events;
15using System.Threading.Tasks;
16
18{
22 public partial class LogView : UserControl, ITabView
23 {
24 private readonly string identifier;
25 private LogSink sink;
26
32 public LogView(string Identifier, bool Register)
33 {
34 this.identifier = Identifier;
35
37
38 if (Register)
39 {
40 this.sink = new LogSink(this);
41 Log.Register(this.sink);
42 }
43 }
44
48 public string Identifier => this.identifier;
49
53 public LogSink Sink => this.sink;
54
55 public void Dispose()
56 {
57 if (!(this.sink is null))
58 {
59 Log.Unregister(this.sink);
60 this.sink = null;
61 }
62 }
63
64 public void Add(LogItem Item)
65 {
66 MainWindow.UpdateGui(this.AddItem, Item);
67 }
68
69 private Task AddItem(object P)
70 {
71 this.LogListView.Items.Add(P);
72 this.LogListView.ScrollIntoView(P);
73
74 return Task.CompletedTask;
75 }
76
77 public void NewButton_Click(object Sender, RoutedEventArgs e)
78 {
79 this.LogListView.Items.Clear();
80 }
81
82 public void SaveButton_Click(object Sender, RoutedEventArgs e)
83 {
84 this.SaveAsButton_Click(Sender, e);
85 }
86
87 public void SaveAsButton_Click(object Sender, RoutedEventArgs e)
88 {
89 SaveFileDialog Dialog = new SaveFileDialog()
90 {
91 AddExtension = true,
92 CheckPathExists = true,
93 CreatePrompt = false,
94 DefaultExt = "xml",
95 Filter = "XML Files (*.xml)|*.xml|HTML Files (*.html,*.htm)|*.html,*.htm|All Files (*.*)|*.*",
96 Title = "Save log file"
97 };
98
99 bool? Result = Dialog.ShowDialog(MainWindow.FindWindow(this));
100
101 if (Result.HasValue && Result.Value)
102 {
103 try
104 {
105 if (Dialog.FilterIndex == 2)
106 {
107 StringBuilder Xml = new StringBuilder();
108 using (XmlWriter w = XmlWriter.Create(Xml, XML.WriterSettings(true, true)))
109 {
110 this.SaveAsXml(w);
111 }
112
113 string Html = XSL.Transform(Xml.ToString(), eventsToHtml);
114
115 File.WriteAllText(Dialog.FileName, Html, System.Text.Encoding.UTF8);
116 }
117 else
118 {
119 using (FileStream f = File.Create(Dialog.FileName))
120 {
121 using (XmlWriter w = XmlWriter.Create(f, XML.WriterSettings(true, false)))
122 {
123 this.SaveAsXml(w);
124 }
125 }
126 }
127 }
128 catch (Exception ex)
129 {
130 MessageBox.Show(MainWindow.FindWindow(this), ex.Message, "Unable to save file.", MessageBoxButton.OK, MessageBoxImage.Error);
131 }
132 }
133 }
134
135 private static readonly XslCompiledTransform eventsToHtml = XSL.LoadTransform("Waher.Client.WPF.Transforms.EventXmlToHtml.xslt");
136 private static readonly XmlSchema schema = XSL.LoadSchema("Waher.Client.WPF.Schema.EventOutput.xsd");
137 private const string logNamespace = "http://waher.se/Schema/EventOutput.xsd";
138 private const string logRoot = "EventOutput";
139
140 private void SaveAsXml(XmlWriter w)
141 {
142 w.WriteStartElement(logRoot, logNamespace);
143
144 foreach (LogItem Item in this.LogListView.Items)
145 {
146 Event Event = Item.Event;
147
148 w.WriteStartElement(Event.Type.ToString());
149 w.WriteAttributeString("timestamp", Encode(Event.Timestamp));
150 w.WriteAttributeString("level", Event.Level.ToString());
151
152
153 if (!string.IsNullOrEmpty(Event.EventId))
154 w.WriteAttributeString("id", Event.EventId);
155
156 if (!string.IsNullOrEmpty(Event.Object))
157 w.WriteAttributeString("object", Event.Object);
158
159 if (!string.IsNullOrEmpty(Event.Actor))
160 w.WriteAttributeString("actor", Event.Actor);
161
162 if (!string.IsNullOrEmpty(Event.Module))
163 w.WriteAttributeString("module", Event.Module);
164
165 if (!string.IsNullOrEmpty(Event.Facility))
166 w.WriteAttributeString("facility", Event.Facility);
167
168 w.WriteStartElement("Message");
169
170 foreach (string Row in GetRows(Event.Message))
171 w.WriteElementString("Row", Row);
172
173 w.WriteEndElement();
174
175 if (!(Event.Tags is null) && Event.Tags.Length > 0)
176 {
177 foreach (KeyValuePair<string, object> Tag in Event.Tags)
178 {
179 w.WriteStartElement("Tag");
180 w.WriteAttributeString("key", Tag.Key);
181
182 if (!(Tag.Value is null))
183 w.WriteAttributeString("value", Tag.Value.ToString());
184
185 w.WriteEndElement();
186 }
187 }
188
189 if (Event.Type >= EventType.Critical && !string.IsNullOrEmpty(Event.StackTrace))
190 {
191 w.WriteStartElement("StackTrace");
192
193 foreach (string Row in GetRows(Event.StackTrace))
194 w.WriteElementString("Row", Row);
195
196 w.WriteEndElement();
197 }
198
199 w.WriteEndElement();
200 w.Flush();
201 }
202
203 w.WriteEndElement();
204 w.Flush();
205 }
206
207 private static string[] GetRows(string s)
208 {
209 return s.Replace("\r\n", "\n").Replace("\r", "\n").Split('\n');
210 }
211
212 internal static string Encode(DateTime DT)
213 {
214 StringBuilder sb = new StringBuilder();
215
216 sb.Append(DT.Year.ToString("D4"));
217 sb.Append('-');
218 sb.Append(DT.Month.ToString("D2"));
219 sb.Append('-');
220 sb.Append(DT.Day.ToString("D2"));
221 sb.Append('T');
222 sb.Append(DT.Hour.ToString("D2"));
223 sb.Append(':');
224 sb.Append(DT.Minute.ToString("D2"));
225 sb.Append(':');
226 sb.Append(DT.Second.ToString("D2"));
227 sb.Append('.');
228 sb.Append(DT.Millisecond.ToString("D3"));
229
230 if (DT.Kind == DateTimeKind.Utc)
231 sb.Append("Z");
232
233 return sb.ToString();
234 }
235
236 public void OpenButton_Click(object Sender, RoutedEventArgs e)
237 {
238 try
239 {
240 OpenFileDialog Dialog = new OpenFileDialog()
241 {
242 AddExtension = true,
243 CheckFileExists = true,
244 CheckPathExists = true,
245 DefaultExt = "xml",
246 Filter = "XML Files (*.xml)|*.xml|All Files (*.*)|*.*",
247 Multiselect = false,
248 ShowReadOnly = true,
249 Title = "Open log file"
250 };
251
252 bool? Result = Dialog.ShowDialog(MainWindow.FindWindow(this));
253
254 if (Result.HasValue && Result.Value)
255 {
256 XmlDocument Xml = new XmlDocument()
257 {
258 PreserveWhitespace = true
259 };
260 Xml.Load(Dialog.FileName);
261
262 this.Load(Xml, Dialog.FileName);
263 }
264 }
265 catch (Exception ex)
266 {
267 ex = Log.UnnestException(ex);
268 MessageBox.Show(ex.Message, "Unable to load file.", MessageBoxButton.OK, MessageBoxImage.Error);
269 }
270 }
271
272 public void Load(XmlDocument Xml, string FileName)
273 {
274 XmlElement E, E2, E3;
275
276 XSL.Validate(FileName, Xml, logRoot, logNamespace, schema);
277
278 this.LogListView.Items.Clear();
279
280 foreach (XmlNode N in Xml.DocumentElement.ChildNodes)
281 {
282 E = N as XmlElement;
283 if (E is null)
284 continue;
285
286 if (!Enum.TryParse(E.LocalName, out EventType Type))
287 continue;
288
289 DateTime Timestamp = XML.Attribute(E, "timestamp", DateTime.MinValue);
290 EventLevel Level = XML.Attribute(E, "level", EventLevel.Minor);
291 string EventId = XML.Attribute(E, "id");
292 string Object = XML.Attribute(E, "object");
293 string Actor = XML.Attribute(E, "actor");
294 string Module = XML.Attribute(E, "module");
295 string Facility = XML.Attribute(E, "facility");
296 StringBuilder Message = new StringBuilder();
297 StringBuilder StackTrace = null;
298 List<KeyValuePair<string, object>> Tags = new List<KeyValuePair<string, object>>();
299
300 foreach (XmlNode N2 in E.ChildNodes)
301 {
302 E2 = N2 as XmlElement;
303 if (E2 is null)
304 continue;
305
306 switch (E2.LocalName)
307 {
308 case "Message":
309 foreach (XmlNode N3 in E2.ChildNodes)
310 {
311 E3 = N3 as XmlElement;
312 if (E3 is null)
313 continue;
314
315 if (E3.LocalName == "Row")
316 Message.AppendLine(E3.InnerText);
317 }
318 break;
319
320 case "Tag":
321 string Key = XML.Attribute(E2, "key");
322 string Value = XML.Attribute(E2, "value");
323
324 Tags.Add(new KeyValuePair<string, object>(Key, Value));
325 break;
326
327 case "StackTrace":
328 if (StackTrace is null)
329 StackTrace = new StringBuilder();
330
331 foreach (XmlNode N3 in E2.ChildNodes)
332 {
333 E3 = N3 as XmlElement;
334 if (E3 is null)
335 continue;
336
337 if (E3.LocalName == "Row")
338 StackTrace.AppendLine(E3.InnerText);
339 }
340 break;
341 }
342 }
343
344 Event Event = new Event(Timestamp, Type, Message.ToString(), Object, Actor, EventId, Level, Facility, Module,
345 StackTrace?.ToString() ?? string.Empty, Tags.ToArray());
346
347 this.Add(new LogItem(Event));
348 }
349 }
350
351 private void UserControl_SizeChanged(object Sender, SizeChangedEventArgs e)
352 {
353 if (this.LogListView.View is GridView GridView)
354 {
355 double w = this.ActualWidth;
356 int i;
357
358 for (i = 0; i < 6; i++)
359 w -= (GridView.Columns[i].ActualWidth + SystemParameters.VerticalScrollBarWidth + 8);
360
361 GridView.Columns[6].Width = Math.Max(w, 10);
362 }
363 }
364
365 }
366}
Interaction logic for LogView.xaml
Definition: LogView.xaml.cs:23
void InitializeComponent()
InitializeComponent
Definition: LogView.g.cs:58
string Identifier
Identifier of log view.
Definition: LogView.xaml.cs:48
LogView(string Identifier, bool Register)
Interaction logic for LogView.xaml
Definition: LogView.xaml.cs:32
LogSink Sink
Log sink registered with Log, if registered, null otherwise.
Definition: LogView.xaml.cs:53
Represents one item in an event log output.
Definition: LogItem.cs:14
Interaction logic for xaml
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:914
static XmlWriterSettings WriterSettings(bool Indent, bool OmitXmlDeclaration)
Gets an XML writer settings object.
Definition: XML.cs:1177
Static class managing loading of XSL resources stored as embedded resources or in content files.
Definition: XSL.cs:15
static XmlSchema LoadSchema(string ResourceName)
Loads an XML schema from an embedded resource.
Definition: XSL.cs:23
static XslCompiledTransform LoadTransform(string ResourceName)
Loads an XSL transformation from an embedded resource.
Definition: XSL.cs:70
static string Transform(string XML, XslCompiledTransform Transform)
Transforms an XML document using an XSL transform.
Definition: XSL.cs:162
static void Validate(string ObjectID, XmlDocument Xml, params XmlSchema[] Schemas)
Validates an XML document given a set of XML schemas.
Definition: XSL.cs:118
Class representing an event.
Definition: Event.cs:10
string Message
Free-text event message.
Definition: Event.cs:131
EventType Type
Type of event.
Definition: Event.cs:121
string Object
Object related to the event.
Definition: Event.cs:136
EventLevel Level
Event Level.
Definition: Event.cs:126
string Actor
Actor responsible for the action causing the event.
Definition: Event.cs:141
string Module
Module where the event is reported.
Definition: Event.cs:156
DateTime Timestamp
Timestamp of event.
Definition: Event.cs:116
KeyValuePair< string, object >[] Tags
Variable set of tags providing event-specific information.
Definition: Event.cs:166
string EventId
Computer-readable Event ID identifying type of even.
Definition: Event.cs:146
string Facility
Facility can be either a facility in the network sense or in the system sense.
Definition: Event.cs:151
string StackTrace
Stack Trace of event.
Definition: Event.cs:161
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static void Register(IEventSink EventSink)
Registers an event sink with the event log. Call Unregister(IEventSink) to unregister it,...
Definition: Log.cs:29
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Definition: Log.cs:818
static bool Unregister(IEventSink EventSink)
Unregisters an event sink from the event log.
Definition: Log.cs:46
Interface for tab view user controls in the client.
Definition: ITabView.cs:10
EventLevel
Event level.
Definition: EventLevel.cs:7
EventType
Type of event.
Definition: EventType.cs:7