Skip to content

Commit 1b9a643

Browse files
committed
**API.Performance** implemented to collect server performance indicators:
* Add the `API_PERFORMANCE_ENABLED` key in the `AppSettings` of the **Web.config** * If enabled, it requires the `TD_PERFORMANCE` table to be created in the DB. Run `root/db/td_performance.sql` to create the table.
1 parent 5b5016c commit 1b9a643

23 files changed

+385
-101
lines changed

db/td_logging.sql

1.21 KB
Binary file not shown.

db/td_performance.sql

2.15 KB
Binary file not shown.

rls/API.Library.dll

4 KB
Binary file not shown.

rls/API.Library.dll.config

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@
119119
<!-- MemCacheD - Salsa code to isolate the cache records form other applications or environments -->
120120
<add key="API_MEMCACHED_SALSA" value="domain.extension" />
121121

122+
<!--
123+
**********************************************************************
124+
API - Performance
125+
**********************************************************************
126+
-->
127+
<!-- Performance - Switch on [TRUE] or off [FALSE] the Performance -->
128+
<add key="API_PERFORMANCE_ENABLED" value="FALSE" />
129+
122130
</AppSettings>
123131

124132
<!--

rls/API.Library.pdb

10 KB
Binary file not shown.

src/API.Library/API.Library.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@
114114
<Compile Include="Entities\MemCacheD.cs" />
115115
<Compile Include="Entities\eMail\eMail.cs" />
116116
<Compile Include="Entities\ADO.cs" />
117+
<Compile Include="Entities\Performance.cs" />
118+
<Compile Include="Entities\Performance.ADO.cs" />
117119
<Compile Include="Entities\ReCAPTCHA.cs" />
118120
<Compile Include="Entities\Utility.cs" />
119121
<Compile Include="Properties\AssemblyInfo.cs" />

src/API.Library/App.config

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@
119119
<!-- MemCacheD - Salsa code to isolate the cache records form other applications or environments -->
120120
<add key="API_MEMCACHED_SALSA" value="domain.extension" />
121121

122+
<!--
123+
**********************************************************************
124+
API - Performance
125+
**********************************************************************
126+
-->
127+
<!-- Performance - Switch on [TRUE] or off [FALSE] the Performance -->
128+
<add key="API_PERFORMANCE_ENABLED" value="FALSE" />
129+
122130
</AppSettings>
123131

124132
<!--

src/API.Library/Entities/API.JSONRPC.cs

Lines changed: 85 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
using System.Collections.Generic;
44
using System.Collections.Specialized;
55
using System.Configuration;
6+
using System.Diagnostics;
67
using System.Linq;
78
using System.Reflection;
89
using System.Text.RegularExpressions;
10+
using System.Threading;
911
using System.Web;
1012
using System.Web.SessionState;
1113

@@ -45,76 +47,103 @@ public class JSONRPC : Common, IHttpHandler, IRequiresSessionState
4547
/// <param name="context"></param>
4648
public void ProcessRequest(HttpContext context)
4749
{
48-
Log.Instance.Info("API Interface Opened");
50+
// Initiate Stopwatch
51+
Stopwatch sw = new Stopwatch();
52+
// Start Stopwatch
53+
sw.Start();
4954

50-
// Set HTTP Requests
51-
httpGET = GetHttpGET();
52-
httpPOST = GetHttpPOST();
55+
// Thread a PerfomanceCollector
56+
PerfomanceCollector performanceCollector = new PerfomanceCollector();
57+
Thread performanceThread = new Thread(new ThreadStart(performanceCollector.CollectData));
58+
performanceThread.Start();
5359

54-
// Set Mime-Type for the Content Type and override the Charset
55-
context.Response.ContentType = JSONRPC_MimeType;
56-
context.Response.Charset = null;
57-
// Set CacheControl to no-cache
58-
context.Response.CacheControl = "no-cache";
60+
try
61+
{
62+
Log.Instance.Info("API Interface Opened");
5963

60-
// Deserialize and parse the JSON request into an Object dynamically
61-
JSONRPC_Request JSONRPC_Request = ParseRequest(ref context);
64+
// Set HTTP Requests
65+
httpGET = GetHttpGET();
66+
httpPOST = GetHttpPOST();
6267

63-
// Check for the maintenance flag
64-
if (Maintenance)
65-
{
66-
JSONRPC_Error error = new JSONRPC_Error { code = -32001, data = "The system is currently under maintenance." };
67-
ParseError(ref context, JSONRPC_Request.id, error);
68-
}
68+
// Set Mime-Type for the Content Type and override the Charset
69+
context.Response.ContentType = JSONRPC_MimeType;
70+
context.Response.Charset = null;
71+
// Set CacheControl to no-cache
72+
context.Response.CacheControl = "no-cache";
6973

70-
// Authenticate and append credentials
71-
if (Authenticate(ref context) == false)
72-
{
73-
JSONRPC_Error error = new JSONRPC_Error { code = -32002 };
74-
ParseError(ref context, JSONRPC_Request.id, error);
75-
}
74+
// Deserialize and parse the JSON request into an Object dynamically
75+
JSONRPC_Request JSONRPC_Request = ParseRequest(ref context);
7676

77-
// Get results from the relevant method with the params
78-
JSONRPC_Output result = GetResult(ref context, JSONRPC_Request);
79-
if (result == null)
80-
{
81-
JSONRPC_Error error = new JSONRPC_Error { code = -32603 };
82-
ParseError(ref context, JSONRPC_Request.id, error);
83-
}
84-
else if (result.error != null)
85-
{
86-
JSONRPC_Error error = new JSONRPC_Error { code = -32099, data = result.error };
87-
ParseError(ref context, JSONRPC_Request.id, error);
88-
}
89-
else
90-
{
91-
// Check if the result.data is already a JSON type casted as: new JRaw(data);
92-
var jsonRaw = result.data as JRaw;
93-
if (jsonRaw != null)
77+
// Check for the maintenance flag
78+
if (Maintenance)
9479
{
95-
JSONRPC_API_ResponseDataJRaw output = new JSONRPC_API_ResponseDataJRaw
96-
{
97-
jsonrpc = JSONRPC_Request.jsonrpc,
98-
result = jsonRaw,
99-
id = JSONRPC_Request.id
100-
};
101-
// Output the JSON-RPC repsonse with JRaw data
102-
context.Response.Write(Utility.JsonSerialize_IgnoreLoopingReference(output));
80+
JSONRPC_Error error = new JSONRPC_Error { code = -32001, data = "The system is currently under maintenance." };
81+
ParseError(ref context, JSONRPC_Request.id, error);
82+
}
83+
84+
// Authenticate and append credentials
85+
if (Authenticate(ref context) == false)
86+
{
87+
JSONRPC_Error error = new JSONRPC_Error { code = -32002 };
88+
ParseError(ref context, JSONRPC_Request.id, error);
89+
}
90+
91+
// Get results from the relevant method with the params
92+
JSONRPC_Output result = GetResult(ref context, JSONRPC_Request);
93+
if (result == null)
94+
{
95+
JSONRPC_Error error = new JSONRPC_Error { code = -32603 };
96+
ParseError(ref context, JSONRPC_Request.id, error);
97+
}
98+
else if (result.error != null)
99+
{
100+
JSONRPC_Error error = new JSONRPC_Error { code = -32099, data = result.error };
101+
ParseError(ref context, JSONRPC_Request.id, error);
103102
}
104103
else
105104
{
106-
JSONRPC_API_ResponseData output = new JSONRPC_API_ResponseData
105+
// Check if the result.data is already a JSON type casted as: new JRaw(data);
106+
var jsonRaw = result.data as JRaw;
107+
if (jsonRaw != null)
107108
{
108-
jsonrpc = JSONRPC_Request.jsonrpc,
109-
result = result.data,
110-
id = JSONRPC_Request.id
111-
};
112-
// Output the JSON-RPC repsonse
113-
context.Response.Write(Utility.JsonSerialize_IgnoreLoopingReference(output));
109+
JSONRPC_API_ResponseDataJRaw output = new JSONRPC_API_ResponseDataJRaw
110+
{
111+
jsonrpc = JSONRPC_Request.jsonrpc,
112+
result = jsonRaw,
113+
id = JSONRPC_Request.id
114+
};
115+
// Output the JSON-RPC repsonse with JRaw data
116+
context.Response.Write(Utility.JsonSerialize_IgnoreLoopingReference(output));
117+
}
118+
else
119+
{
120+
JSONRPC_API_ResponseData output = new JSONRPC_API_ResponseData
121+
{
122+
jsonrpc = JSONRPC_Request.jsonrpc,
123+
result = result.data,
124+
id = JSONRPC_Request.id
125+
};
126+
// Output the JSON-RPC repsonse
127+
context.Response.Write(Utility.JsonSerialize_IgnoreLoopingReference(output));
128+
}
114129
}
115130
}
131+
catch (Exception e)
132+
{
133+
Log.Instance.Fatal(e);
134+
throw;
135+
}
136+
finally
137+
{
138+
// Terminate Perfomance collection
139+
performanceThread.Abort();
116140

117-
Log.Instance.Info("API Interface Closed");
141+
// Stop Stopwatch
142+
sw.Stop();
143+
144+
Log.Instance.Info("API Execution Time (s): " + ((float)Math.Round(sw.Elapsed.TotalMilliseconds / 1000, 3)).ToString());
145+
Log.Instance.Info("API Interface Closed");
146+
}
118147
}
119148

120149
/// <summary>

src/API.Library/Entities/API.RESTful.cs

Lines changed: 69 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Collections.Specialized;
4+
using System.Diagnostics;
45
using System.Linq;
56
using System.Net;
67
using System.Net.Mime;
78
using System.Reflection;
89
using System.Text.RegularExpressions;
10+
using System.Threading;
911
using System.Web;
1012
using System.Web.SessionState;
1113

@@ -31,64 +33,92 @@ public class RESTful : Common, IHttpHandler, IRequiresSessionState
3133
/// <param name="context"></param>
3234
public void ProcessRequest(HttpContext context)
3335
{
34-
Log.Instance.Info("API Interface Opened");
36+
// Initiate Stopwatch
37+
Stopwatch sw = new Stopwatch();
38+
// Start Stopwatch
39+
sw.Start();
3540

36-
// Set HTTP Requests
37-
httpGET = GetHttpGET();
38-
httpPOST = GetHttpPOST();
41+
// Thread a PerfomanceCollector
42+
PerfomanceCollector performanceCollector = new PerfomanceCollector();
43+
Thread performanceThread = new Thread(new ThreadStart(performanceCollector.CollectData));
44+
performanceThread.Start();
3945

40-
// Set Mime-Type for the Content Type and override the Charset
41-
context.Response.Charset = null;
42-
// Set CacheControl to no-cache
43-
context.Response.CacheControl = "no-cache";
44-
45-
// Extract the request parameters from the URL
46-
ParseRequest(ref context);
47-
48-
// Check for the maintenance flag
49-
if (Maintenance)
46+
try
5047
{
51-
ParseError(ref context, HttpStatusCode.ServiceUnavailable, "System maintenance");
52-
}
48+
Log.Instance.Info("API Interface Opened");
5349

54-
// Authenticate and append credentials
55-
if (Authenticate(ref context) == false)
56-
{
57-
ParseError(ref context, HttpStatusCode.Unauthorized, "Invalid authentication");
58-
}
50+
// Set HTTP Requests
51+
httpGET = GetHttpGET();
52+
httpPOST = GetHttpPOST();
5953

60-
// Get results from the relevant method with the params
61-
RESTful_Output result = GetResult(ref context);
54+
// Set Mime-Type for the Content Type and override the Charset
55+
context.Response.Charset = null;
56+
// Set CacheControl to no-cache
57+
context.Response.CacheControl = "no-cache";
6258

63-
if (result == null)
64-
{
65-
ParseError(ref context, HttpStatusCode.InternalServerError, "Internal Error");
66-
}
67-
else if (result.statusCode == HttpStatusCode.OK)
68-
{
69-
context.Response.StatusCode = (int)result.statusCode;
70-
context.Response.ContentType = result.mimeType;
59+
// Extract the request parameters from the URL
60+
ParseRequest(ref context);
7161

72-
if (!String.IsNullOrEmpty(result.fileName))
62+
// Check for the maintenance flag
63+
if (Maintenance)
7364
{
74-
context.Response.AppendHeader("Content-Disposition", new ContentDisposition { Inline = true, FileName = result.fileName }.ToString());
65+
ParseError(ref context, HttpStatusCode.ServiceUnavailable, "System maintenance");
7566
}
7667

77-
if (result.response?.GetType() == typeof(byte[]))
68+
// Authenticate and append credentials
69+
if (Authenticate(ref context) == false)
7870
{
79-
context.Response.BinaryWrite(result.response);
71+
ParseError(ref context, HttpStatusCode.Unauthorized, "Invalid authentication");
72+
}
73+
74+
// Get results from the relevant method with the params
75+
RESTful_Output result = GetResult(ref context);
76+
77+
if (result == null)
78+
{
79+
ParseError(ref context, HttpStatusCode.InternalServerError, "Internal Error");
80+
}
81+
else if (result.statusCode == HttpStatusCode.OK)
82+
{
83+
context.Response.StatusCode = (int)result.statusCode;
84+
context.Response.ContentType = result.mimeType;
85+
86+
if (!String.IsNullOrEmpty(result.fileName))
87+
{
88+
context.Response.AppendHeader("Content-Disposition", new ContentDisposition { Inline = true, FileName = result.fileName }.ToString());
89+
}
90+
91+
if (result.response?.GetType() == typeof(byte[]))
92+
{
93+
context.Response.BinaryWrite(result.response);
94+
}
95+
else
96+
{
97+
context.Response.Write(result.response);
98+
}
8099
}
81100
else
82101
{
83-
context.Response.Write(result.response);
102+
ParseError(ref context, result.statusCode, result.response);
84103
}
104+
85105
}
86-
else
106+
catch (Exception e)
87107
{
88-
ParseError(ref context, result.statusCode, result.response);
108+
Log.Instance.Fatal(e);
109+
throw;
89110
}
111+
finally
112+
{
113+
// Terminate Perfomance collection
114+
performanceThread.Abort();
90115

91-
Log.Instance.Info("API Interface Closed");
116+
// Stop Stopwatch
117+
sw.Stop();
118+
119+
Log.Instance.Info("API Execution Time (s): " + ((float)Math.Round(sw.Elapsed.TotalMilliseconds / 1000, 3)).ToString());
120+
Log.Instance.Info("API Interface Closed");
121+
}
92122
}
93123

94124
/// <summary>

0 commit comments

Comments
 (0)