2using System.Collections.Generic;
5using System.Threading.Tasks;
20 [Page(1,
"Time", 150)]
22 [ToolTip(3,
"Search for records from this point in time.")]
23 public DateTime From = DateTime.MinValue;
25 [Page(1,
"Time", 150)]
27 [ToolTip(5,
"Search for records to this point in time.")]
28 public DateTime To = DateTime.MaxValue;
56 throw new NotSupportedException();
61 return Task.FromResult(
string.Empty);
66 return Task.FromResult(
string.Empty);
71 return Task.FromResult(
string.Empty);
77 return Task.CompletedTask;
87 if (this.To < this.From)
89 DateTime Temp = this.To;
94 List<Filter> Filters =
new List<Filter>();
95 IEnumerable<HttpStatistic> Records;
97 if (this.From > DateTime.MinValue)
100 if (this.To < DateTime.MaxValue)
105 switch (Filters.Count)
108 Records = await
Database.
Find<HttpStatistic>(
"Timestamp");
112 Records = await
Database.
Find<HttpStatistic>(Filters[0],
"Timestamp");
125 foreach (HttpStatistic
Record in Records)
128 const int MaxRecords = 50;
129 bool ShowTable = NrRecords <= MaxRecords;
149 StringBuilder Markdown =
new StringBuilder();
152 Markdown.Append(
" **");
153 Markdown.Append(NrRecords.ToString());
154 Markdown.Append(
"**. (");
155 Markdown.Append((await
Language.
GetStringAsync(typeof(HttpStatistics), 19,
"Table shown if %0% records or less.")).Replace(
"%0%", MaxRecords.ToString()));
156 Markdown.Append(
")");
161 SortedDictionary<string, double> PerMethod =
new SortedDictionary<string, double>();
162 SortedDictionary<string, double> PerUserAgent =
new SortedDictionary<string, double>();
163 SortedDictionary<string, double> PerFrom =
new SortedDictionary<string, double>();
164 SortedDictionary<string, double> PerResource =
new SortedDictionary<string, double>();
165 List<DateTime> Timestamps =
new List<DateTime>();
166 List<double> NrCalls =
new List<double>();
167 List<double> NrRx =
new List<double>();
168 List<double> NrTx =
new List<double>();
169 double MaxNrCalls = 0;
172 double DivisorNrCalls = 1;
173 double DivisorNrRx = 1;
174 double DivisorNrTx = 1;
175 string PrefixNrCalls =
string.Empty;
176 string PrefixNrRx =
string.Empty;
177 string PrefixNrTx =
string.Empty;
179 foreach (HttpStatistic Rec
in Records)
193 Timestamps.Add(Rec.Timestamp);
194 NrCalls.Add(Rec.NrCalls);
195 NrRx.Add(Rec.NrBytesRx);
196 NrTx.Add(Rec.NrBytesTx);
198 if (Rec.NrCalls > MaxNrCalls)
199 MaxNrCalls = Rec.NrCalls;
201 if (Rec.NrBytesRx > MaxNrRx)
202 MaxNrRx = Rec.NrBytesRx;
204 if (Rec.NrBytesTx > MaxNrTx)
205 MaxNrTx = Rec.NrBytesTx;
207 Accumulate(PerMethod, Rec.CallsPerMethod,
null);
208 Accumulate(PerUserAgent, Rec.CallsPerUserAgent, (s) =>
210 StringBuilder sb = new StringBuilder();
211 bool InParenthesis = false;
212 bool Removed = false;
214 foreach (char ch in s)
220 InParenthesis = false;
231 if (ch >=
'0' && ch <=
'9')
236 InParenthesis = true;
244 return sb.ToString();
246 Accumulate(PerFrom, Rec.CallsPerFrom, (s) =>
250 if (IPAddress.TryParse(s, out _))
252 else if ((i = s.IndexOf(
'@')) > 0 & (j = s.LastIndexOf(
'/')) > 0 && j > i)
253 s = s.Substring(0, j);
257 Accumulate(PerResource, Rec.CallsPerResource,
null);
260 ScaleAmounts(MaxNrCalls, 1000, ref DivisorNrCalls, ref PrefixNrCalls);
261 ScaleAmounts(MaxNrRx, 1024, ref DivisorNrRx, ref PrefixNrRx);
262 ScaleAmounts(MaxNrTx, 1024, ref DivisorNrTx, ref PrefixNrTx);
264 if (DivisorNrRx < DivisorNrTx)
266 DivisorNrRx = DivisorNrTx;
267 PrefixNrRx = PrefixNrTx;
275 "G:=plot2dline(Timestamps,NrCalls/" + DivisorNrCalls.ToString() +
",'Red');" +
277 "G.LabelX:=LabelX;" +
278 "G.LabelY:=LabelY;" +
284 {
"Timestamps", Timestamps.ToArray() },
285 {
"NrCalls", NrCalls.ToArray() },
293 "G:=plot2dline(Timestamps,NrRx/" + DivisorNrTx.ToString() +
",'Blue')+" +
294 "plot2dline(Timestamps,NrTx/" + DivisorNrTx.ToString() +
",'Red');" +
296 "G.LabelX:=LabelX;" +
297 "G.LabelY:=LabelY;" +
303 {
"Timestamps", Timestamps.ToArray() },
304 {
"NrRx", NrRx.ToArray() },
305 {
"NrTx", NrTx.ToArray() },
306 {
"Title", await
Language.
GetStringAsync(typeof(HttpStatistics), 28,
"HTTP Bytes Transmitted over time") },
311 "legend(['NrRx','NrTx'],['Blue','Red'],'White',2)"));
313 double Height = 100 + 20 * PerMethod.Count;
314 double Scale = Height > 8000 ? Scale = 8000 / Height : 1;
315 double Max = CalcMax(PerMethod);
317 string Prefix =
string.Empty;
318 ScaleAmounts(Max, 1000, ref Divisor, ref Prefix);
322 "G:=horizontalbars(" +
323 "[foreach Label in PerMethod.Keys: Left(Label,50)]," +
324 "[foreach Value in PerMethod.Values: Value/Divisor]);" +
326 "G.LabelX:=LabelX;" +
327 "G.LabelY:=LabelY;" +
334 {
"Divisor", Divisor },
335 {
"PerMethod", PerMethod },
341 Height = 100 + 20 * PerUserAgent.Count;
342 Scale = Height > 8000 ? Scale = 8000 / Height : 1;
343 Max = CalcMax(PerUserAgent);
346 ScaleAmounts(Max, 1000, ref Divisor, ref Prefix);
350 "G:=horizontalbars(" +
351 "[foreach Label in PerUserAgent.Keys: Left(Label,50)]," +
352 "[foreach Value in PerUserAgent.Values: Value/Divisor]);" +
354 "G.LabelX:=LabelX;" +
355 "G.LabelY:=LabelY;" +
362 {
"Divisor", Divisor },
363 {
"PerUserAgent", PerUserAgent },
366 {
"LabelY",
"User-Agent" }
369 Height = 100 + 20 * PerFrom.Count;
370 Scale = Height > 8000 ? Scale = 8000 / Height : 1;
371 Max = CalcMax(PerFrom);
374 ScaleAmounts(Max, 1000, ref Divisor, ref Prefix);
378 "G:=horizontalbars(" +
379 "[foreach Label in PerFrom.Keys: Left(Label,50)]," +
380 "[foreach Value in PerFrom.Values: Value/Divisor]);" +
382 "G.LabelX:=LabelX;" +
383 "G.LabelY:=LabelY;" +
390 {
"Divisor", Divisor },
391 {
"PerFrom", PerFrom },
397 Height = 100 + 20 * PerResource.Count;
398 Scale = Height > 8000 ? Scale = 8000 / Height : 1;
399 Max = CalcMax(PerResource);
402 ScaleAmounts(Max, 1000, ref Divisor, ref Prefix);
406 "G:=horizontalbars(" +
407 "[foreach Label in PerResource.Keys: Left(Label,50)]," +
408 "[foreach Value in PerResource.Values: Value/Divisor]);" +
410 "G.LabelX:=LabelX;" +
411 "G.LabelY:=LabelY;" +
418 {
"Divisor", Divisor },
419 {
"PerResource", PerResource },
438 private static double CalcMax(SortedDictionary<string, double> Accumulated)
442 foreach (
double d
in Accumulated.Values)
451 private delegate
string ReduceCallback(
string s);
453 private static void Accumulate(SortedDictionary<string, double> Accumulated, PersistedData.Commands.Statistic[] Statistics, ReduceCallback ReduceEndpoint)
455 if (!(Statistics is
null))
457 foreach (PersistedData.Commands.Statistic Statistic in Statistics)
459 string s = Statistic.Name;
461 if (!(ReduceEndpoint is
null))
462 s = ReduceEndpoint(s);
464 if (!Accumulated.TryGetValue(s, out
double Count))
467 Accumulated[s] = Count + Statistic.Count;
472 private static void ScaleAmounts(
double Value,
double Thousand, ref
double Divisor, ref
string Prefix)
Class that can be used to encapsulate Markdown to be returned from a Web Service, bypassing any encod...
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
This filter selects objects that conform to all child-filters provided.
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 information about a language.
Task< string > GetStringAsync(Type Type, int Id, string Default)
Gets the string value of a string ID. If no such string exists, a string is created with the default ...
Class managing a script expression.
static Task< object > EvalAsync(string Script)
Evaluates script, in string format.
const string GraphHeightVariableName
Variable name for graph height
const string GraphWidthVariableName
Variable name for graph width
const string GraphLabelFontSizeVariableName
Variable name for graph label font size
Task< string > GetNameAsync(Language Language)
Gets the name of data source.
string CommandID
ID of command.
CommandType Type
Type of command.
string SortKey
Sort Key, if available.
Task< string > GetSuccessStringAsync(Language Language)
Gets a success string, if any, of the command. If no specific success string is available,...
string SortCategory
Sort Category, if available.
Task StartQueryExecutionAsync(Query Query, Language Language)
Starts the execution of a query.
Task< bool > CanExecuteAsync(RequestOrigin Caller)
If the command can be executed by the caller.
ICommand Copy()
Creates a copy of the command object.
Task< string > GetFailureStringAsync(Language Language)
Gets a failure string, if any, of the command. If no specific failure string is available,...
Task< string > GetConfirmationStringAsync(Language Language)
Gets a confirmation string, if any, of the command. If no confirmation is necessary,...
Task ExecuteCommandAsync()
Executes the command.
Service Module hosting the XMPP broker and its components.
Defines a column in a table.
Class handling the reception of data from a query.
Task TableDone(string TableId)
Reports a table as being complete.
Task EndSection()
Ends a section. Each call to BeginSection(string) must be followed by a call to EndSection().
Task NewObject(object Object)
Reports a new object.
Task Start()
Starts query execution.
Task NewRecords(string TableId, params Record[] Records)
Reports a new set of records in a table.
Task BeginSection(string Header)
Begins a new section. Sections can be nested. Each call to BeginSection(string) must be followed by a...
Task NewTable(string TableId, string TableName, params Column[] Columns)
Defines a new table in the query output.
Task LogMessage(Exception Exception)
Logs an Exception as a query message.
async Task Done()
Query execution completed.
Task SetStatus(string Status)
Sets the current status of the query execution.
Task SetTitle(string Title)
Sets the title of the report.
Defines a record in a table.
Tokens available in request.
string From
Address of caller.
Prefix
SI prefixes. http://physics.nist.gov/cuu/Units/prefixes.html
ColumnAlignment
Column alignment.