5using System.Threading.Tasks;
33 [Page(1,
"Time", 150)]
35 [ToolTip(3,
"Search for records from this point in time.")]
36 public DateTime From = DateTime.Today.AddDays(-1);
38 [Page(1,
"Time", 150)]
40 [ToolTip(5,
"Search for records to this point in time.")]
41 public DateTime To = DateTime.Today.AddDays(1);
60 return Task.CompletedTask;
70 if (this.To < this.From)
72 DateTime Temp = this.To;
77 List<Filter> Filters =
new List<Filter>();
78 if (this.From > DateTime.MinValue)
81 if (this.To < DateTime.MaxValue)
86 IEnumerable<HttpStatistic> Records = Filters.Count
switch
89 1 => await
Database.
Find<HttpStatistic>(Filters[0],
"Timestamp"),
98 foreach (HttpStatistic
Record in Records)
101 const int MaxRecords = 50;
102 bool ShowTable = NrRecords <= MaxRecords;
122 StringBuilder Markdown =
new StringBuilder();
125 Markdown.Append(
" **");
126 Markdown.Append(NrRecords.ToString());
127 Markdown.Append(
"**. (");
128 Markdown.Append((await
Language.
GetStringAsync(typeof(HttpStatisticsCommand), 19,
"Table shown if %0% records or less.")).Replace(
"%0%", MaxRecords.ToString()));
129 Markdown.Append(
")");
134 SortedDictionary<string, double> PerMethod =
new SortedDictionary<string, double>();
135 SortedDictionary<string, double> PerUserAgent =
new SortedDictionary<string, double>();
136 SortedDictionary<string, double> PerFrom =
new SortedDictionary<string, double>();
137 SortedDictionary<string, double> PerResource =
new SortedDictionary<string, double>();
138 List<DateTime> Timestamps =
new List<DateTime>();
139 List<double> NrCalls =
new List<double>();
140 List<double> NrRx =
new List<double>();
141 List<double> NrTx =
new List<double>();
142 double MaxNrCalls = 0;
145 double DivisorNrCalls = 1;
146 double DivisorNrRx = 1;
147 double DivisorNrTx = 1;
148 string PrefixNrCalls =
string.Empty;
149 string PrefixNrRx =
string.Empty;
150 string PrefixNrTx =
string.Empty;
152 foreach (HttpStatistic Rec
in Records)
166 Timestamps.Add(Rec.Timestamp);
167 NrCalls.Add(Rec.NrCalls);
168 NrRx.Add(Rec.NrBytesRx);
169 NrTx.Add(Rec.NrBytesTx);
171 if (Rec.NrCalls > MaxNrCalls)
172 MaxNrCalls = Rec.NrCalls;
174 if (Rec.NrBytesRx > MaxNrRx)
175 MaxNrRx = Rec.NrBytesRx;
177 if (Rec.NrBytesTx > MaxNrTx)
178 MaxNrTx = Rec.NrBytesTx;
180 Accumulate(PerMethod, Rec.CallsPerMethod,
null);
181 Accumulate(PerUserAgent, Rec.CallsPerUserAgent, (s) =>
183 StringBuilder sb = new StringBuilder();
184 bool InParenthesis = false;
185 bool Removed = false;
187 foreach (char ch in s)
193 InParenthesis = false;
204 if (ch >=
'0' && ch <=
'9')
209 InParenthesis = true;
217 return sb.ToString();
219 Accumulate(PerFrom, Rec.CallsPerFrom, (s) =>
223 if (IPAddress.TryParse(s, out _))
225 else if ((i = s.IndexOf(
'@')) > 0 & (j = s.LastIndexOf(
'/')) > 0 && j > i)
230 Accumulate(PerResource, Rec.CallsPerResource,
null);
233 ScaleAmounts(MaxNrCalls, 1000, ref DivisorNrCalls, ref PrefixNrCalls);
234 ScaleAmounts(MaxNrRx, 1024, ref DivisorNrRx, ref PrefixNrRx);
235 ScaleAmounts(MaxNrTx, 1024, ref DivisorNrTx, ref PrefixNrTx);
237 if (DivisorNrRx < DivisorNrTx)
239 DivisorNrRx = DivisorNrTx;
240 PrefixNrRx = PrefixNrTx;
248 "G:=plot2dline(Timestamps,NrCalls/" + DivisorNrCalls.ToString() +
",'Red');" +
250 "G.LabelX:=LabelX;" +
251 "G.LabelY:=LabelY;" +
257 {
"Timestamps", Timestamps.ToArray() },
258 {
"NrCalls", NrCalls.ToArray() },
261 {
"LabelY", PrefixNrCalls + await
Language.
GetStringAsync(typeof(HttpStatisticsCommand), 27,
"Requests/day") }
266 "G:=plot2dline(Timestamps,NrRx/" + DivisorNrTx.ToString() +
",'Blue')+" +
267 "plot2dline(Timestamps,NrTx/" + DivisorNrTx.ToString() +
",'Red');" +
269 "G.LabelX:=LabelX;" +
270 "G.LabelY:=LabelY;" +
276 {
"Timestamps", Timestamps.ToArray() },
277 {
"NrRx", NrRx.ToArray() },
278 {
"NrTx", NrTx.ToArray() },
279 {
"Title", await
Language.
GetStringAsync(typeof(HttpStatisticsCommand), 28,
"HTTP Bytes Transmitted over time") },
284 "legend(['NrRx','NrTx'],['Blue','Red'],'White',2)"));
286 double Height = 100 + 20 * PerMethod.Count;
287 double Scale = Height > 8000 ? Scale = 8000 / Height : 1;
288 double Max = CalcMax(PerMethod);
290 string Prefix =
string.Empty;
291 ScaleAmounts(Max, 1000, ref Divisor, ref Prefix);
295 "G:=horizontalbars(" +
296 "[foreach Label in PerMethod.Keys: Left(Label,50)]," +
297 "[foreach Value in PerMethod.Values: Value/Divisor]);" +
299 "G.LabelX:=LabelX;" +
300 "G.LabelY:=LabelY;" +
307 {
"Divisor", Divisor },
308 {
"PerMethod", PerMethod },
314 Height = 100 + 20 * PerUserAgent.Count;
315 Scale = Height > 8000 ? Scale = 8000 / Height : 1;
316 Max = CalcMax(PerUserAgent);
319 ScaleAmounts(Max, 1000, ref Divisor, ref Prefix);
323 "G:=horizontalbars(" +
324 "[foreach Label in PerUserAgent.Keys: Left(Label,50)]," +
325 "[foreach Value in PerUserAgent.Values: Value/Divisor]);" +
327 "G.LabelX:=LabelX;" +
328 "G.LabelY:=LabelY;" +
335 {
"Divisor", Divisor },
336 {
"PerUserAgent", PerUserAgent },
339 {
"LabelY",
"User-Agent" }
342 Height = 100 + 20 * PerFrom.Count;
343 Scale = Height > 8000 ? Scale = 8000 / Height : 1;
344 Max = CalcMax(PerFrom);
347 ScaleAmounts(Max, 1000, ref Divisor, ref Prefix);
351 "G:=horizontalbars(" +
352 "[foreach Label in PerFrom.Keys: Left(Label,50)]," +
353 "[foreach Value in PerFrom.Values: Value/Divisor]);" +
355 "G.LabelX:=LabelX;" +
356 "G.LabelY:=LabelY;" +
363 {
"Divisor", Divisor },
364 {
"PerFrom", PerFrom },
370 Height = 100 + 20 * PerResource.Count;
371 Scale = Height > 8000 ? Scale = 8000 / Height : 1;
372 Max = CalcMax(PerResource);
375 ScaleAmounts(Max, 1000, ref Divisor, ref Prefix);
379 "G:=horizontalbars(" +
380 "[foreach Label in PerResource.Keys: Left(Label,50)]," +
381 "[foreach Value in PerResource.Values: Value/Divisor]);" +
383 "G.LabelX:=LabelX;" +
384 "G.LabelY:=LabelY;" +
391 {
"Divisor", Divisor },
392 {
"PerResource", PerResource },
411 private static double CalcMax(SortedDictionary<string, double> Accumulated)
415 foreach (
double d
in Accumulated.Values)
424 private delegate
string ReduceCallback(
string s);
426 private static void Accumulate(SortedDictionary<string, double> Accumulated,
Statistic[] Statistics, ReduceCallback ReduceEndpoint)
428 if (!(Statistics is
null))
434 if (!(ReduceEndpoint is
null))
435 s = ReduceEndpoint(s);
437 if (!Accumulated.TryGetValue(s, out
double Count))
440 Accumulated[s] = Count +
Statistic.Count;
445 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.
ReportNode Report
Report node.
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
Abstract base class for commands executing a server administrator report.
Executes the HTTP Statistics report.
override Task StartQueryExecutionAsync(Query Query, Language Language)
Starts the execution of a query.
HttpStatisticsCommand(HttpProtocol Report)
Executes the HTTP Statistics report.
override ICommand Copy()
Creates a copy of the command object.
override Task< string > GetNameAsync(Language Language)
Gets the displayable name of the command.
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.
Prefix
SI prefixes. http://physics.nist.gov/cuu/Units/prefixes.html
ColumnAlignment
Column alignment.