diff options
author | Teravus Ovares | 2009-01-03 03:30:03 +0000 |
---|---|---|
committer | Teravus Ovares | 2009-01-03 03:30:03 +0000 |
commit | e9cef70f892bfbf4aad0e4471a958367766d849a (patch) | |
tree | 397e078977b430526a2f04041e0dfb9a5fb99156 /OpenSim/Region/UserStatistics | |
parent | Split agent updates into two messages: full update and position+camera update... (diff) | |
download | opensim-SC_OLD-e9cef70f892bfbf4aad0e4471a958367766d849a.zip opensim-SC_OLD-e9cef70f892bfbf4aad0e4471a958367766d849a.tar.gz opensim-SC_OLD-e9cef70f892bfbf4aad0e4471a958367766d849a.tar.bz2 opensim-SC_OLD-e9cef70f892bfbf4aad0e4471a958367766d849a.tar.xz |
* Updates the sim stats module. Cleans out some of the rot.
* Adds a prototype web stats module which is disabled by default. It's functional with one report right now, however, the database structure may change, so I don't recommend enabling this to keep actual stats right now. I'll let you know when it's safe.
* Adds Prototype for ajaxy web content
* removed a warning or two.
Diffstat (limited to 'OpenSim/Region/UserStatistics')
-rw-r--r-- | OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs | 185 | ||||
-rw-r--r-- | OpenSim/Region/UserStatistics/Default_Report.cs | 215 | ||||
-rw-r--r-- | OpenSim/Region/UserStatistics/HTMLUtil.cs | 185 | ||||
-rw-r--r-- | OpenSim/Region/UserStatistics/IStatsReport.cs | 10 | ||||
-rw-r--r-- | OpenSim/Region/UserStatistics/Prototype_distributor.cs | 33 | ||||
-rw-r--r-- | OpenSim/Region/UserStatistics/SimStatsAJAX.cs | 190 | ||||
-rw-r--r-- | OpenSim/Region/UserStatistics/Updater_distributor.cs | 35 | ||||
-rw-r--r-- | OpenSim/Region/UserStatistics/WebStatsModule.cs | 1083 |
8 files changed, 1936 insertions, 0 deletions
diff --git a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs new file mode 100644 index 0000000..2dcd2b8 --- /dev/null +++ b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs | |||
@@ -0,0 +1,185 @@ | |||
1 | using System; | ||
2 | using System.Collections; | ||
3 | using System.Collections.Generic; | ||
4 | using System.Reflection; | ||
5 | using System.Text; | ||
6 | using Mono.Data.SqliteClient; | ||
7 | using OpenMetaverse; | ||
8 | using OpenSim.Region.Environment.Scenes; | ||
9 | using OpenSim.Framework.Statistics; | ||
10 | |||
11 | namespace OpenSim.Region.UserStatistics | ||
12 | { | ||
13 | public class ActiveConnectionsAJAX : IStatsController | ||
14 | { | ||
15 | #region IStatsController Members | ||
16 | |||
17 | public Hashtable ProcessModel(Hashtable pParams) | ||
18 | { | ||
19 | |||
20 | List<Scene> m_scene = (List<Scene>)pParams["Scenes"]; | ||
21 | |||
22 | Hashtable nh = new Hashtable(); | ||
23 | nh.Add("hdata", m_scene); | ||
24 | |||
25 | return nh; | ||
26 | } | ||
27 | |||
28 | public string RenderView(Hashtable pModelResult) | ||
29 | { | ||
30 | List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"]; | ||
31 | |||
32 | StringBuilder output = new StringBuilder(); | ||
33 | HTMLUtil.OL_O(ref output, ""); | ||
34 | foreach (Scene scene in all_scenes) | ||
35 | { | ||
36 | List<ScenePresence> avatarInScene = scene.GetScenePresences(); | ||
37 | |||
38 | HTMLUtil.LI_O(ref output, ""); | ||
39 | output.Append(scene.RegionInfo.RegionName); | ||
40 | HTMLUtil.OL_O(ref output, ""); | ||
41 | foreach (ScenePresence av in avatarInScene) | ||
42 | { | ||
43 | Dictionary<string,string> queues = new Dictionary<string, string>(); | ||
44 | if (av.ControllingClient is IStatsCollector) | ||
45 | { | ||
46 | IStatsCollector isClient = (IStatsCollector) av.ControllingClient; | ||
47 | queues = decodeQueueReport(isClient.Report()); | ||
48 | } | ||
49 | HTMLUtil.LI_O(ref output, ""); | ||
50 | output.Append(av.Name); | ||
51 | output.Append(" "); | ||
52 | output.Append((av.IsChildAgent ? "Child" : "Root")); | ||
53 | |||
54 | Dictionary<string, int> throttles = DecodeClientThrottles(av.ControllingClient.GetThrottlesPacked(1)); | ||
55 | |||
56 | HTMLUtil.UL_O(ref output, ""); | ||
57 | foreach (string throttlename in throttles.Keys) | ||
58 | { | ||
59 | HTMLUtil.LI_O(ref output, ""); | ||
60 | output.Append(throttlename); | ||
61 | output.Append(":"); | ||
62 | output.Append(throttles[throttlename].ToString()); | ||
63 | if (queues.ContainsKey(throttlename)) | ||
64 | { | ||
65 | output.Append("/"); | ||
66 | output.Append(queues[throttlename]); | ||
67 | } | ||
68 | HTMLUtil.LI_C(ref output); | ||
69 | } | ||
70 | if (queues.ContainsKey("Incoming") && queues.ContainsKey("Outgoing")) | ||
71 | { | ||
72 | HTMLUtil.LI_O(ref output, "red"); | ||
73 | output.Append("SEND:"); | ||
74 | output.Append(queues["Outgoing"]); | ||
75 | output.Append("/"); | ||
76 | output.Append(queues["Incoming"]); | ||
77 | HTMLUtil.LI_C(ref output); | ||
78 | } | ||
79 | |||
80 | HTMLUtil.UL_C(ref output); | ||
81 | HTMLUtil.LI_C(ref output); | ||
82 | } | ||
83 | HTMLUtil.OL_C(ref output); | ||
84 | } | ||
85 | HTMLUtil.OL_C(ref output); | ||
86 | return output.ToString(); | ||
87 | } | ||
88 | |||
89 | public Dictionary<string, int> DecodeClientThrottles(byte[] throttle) | ||
90 | { | ||
91 | Dictionary<string, int> returndict = new Dictionary<string, int>(); | ||
92 | // From mantis http://opensimulator.org/mantis/view.php?id=1374 | ||
93 | // it appears that sometimes we are receiving empty throttle byte arrays. | ||
94 | // TODO: Investigate this behaviour | ||
95 | if (throttle.Length == 0) | ||
96 | { | ||
97 | return new Dictionary<string, int>(); | ||
98 | } | ||
99 | |||
100 | int tResend = -1; | ||
101 | int tLand = -1; | ||
102 | int tWind = -1; | ||
103 | int tCloud = -1; | ||
104 | int tTask = -1; | ||
105 | int tTexture = -1; | ||
106 | int tAsset = -1; | ||
107 | int tall = -1; | ||
108 | const int singlefloat = 4; | ||
109 | |||
110 | //Agent Throttle Block contains 7 single floatingpoint values. | ||
111 | int j = 0; | ||
112 | |||
113 | // Some Systems may be big endian... | ||
114 | // it might be smart to do this check more often... | ||
115 | if (!BitConverter.IsLittleEndian) | ||
116 | for (int i = 0; i < 7; i++) | ||
117 | Array.Reverse(throttle, j + i * singlefloat, singlefloat); | ||
118 | |||
119 | // values gotten from OpenMetaverse.org/wiki/Throttle. Thanks MW_ | ||
120 | // bytes | ||
121 | // Convert to integer, since.. the full fp space isn't used. | ||
122 | tResend = (int)BitConverter.ToSingle(throttle, j); | ||
123 | returndict.Add("Resend", tResend); | ||
124 | j += singlefloat; | ||
125 | tLand = (int)BitConverter.ToSingle(throttle, j); | ||
126 | returndict.Add("Land", tLand); | ||
127 | j += singlefloat; | ||
128 | tWind = (int)BitConverter.ToSingle(throttle, j); | ||
129 | returndict.Add("Wind", tWind); | ||
130 | j += singlefloat; | ||
131 | tCloud = (int)BitConverter.ToSingle(throttle, j); | ||
132 | returndict.Add("Cloud", tCloud); | ||
133 | j += singlefloat; | ||
134 | tTask = (int)BitConverter.ToSingle(throttle, j); | ||
135 | returndict.Add("Task", tTask); | ||
136 | j += singlefloat; | ||
137 | tTexture = (int)BitConverter.ToSingle(throttle, j); | ||
138 | returndict.Add("Texture", tTexture); | ||
139 | j += singlefloat; | ||
140 | tAsset = (int)BitConverter.ToSingle(throttle, j); | ||
141 | returndict.Add("Asset", tAsset); | ||
142 | |||
143 | tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset; | ||
144 | returndict.Add("All", tall); | ||
145 | |||
146 | return returndict; | ||
147 | } | ||
148 | public Dictionary<string,string> decodeQueueReport(string rep) | ||
149 | { | ||
150 | Dictionary<string, string> returndic = new Dictionary<string, string>(); | ||
151 | if (rep.Length == 79) | ||
152 | { | ||
153 | int pos = 1; | ||
154 | returndic.Add("All", rep.Substring((6 * pos), 8)); pos++; | ||
155 | returndic.Add("Incoming", rep.Substring((7 * pos), 8)); pos++; | ||
156 | returndic.Add("Outgoing", rep.Substring((7 * pos) , 8)); pos++; | ||
157 | returndic.Add("Resend", rep.Substring((7 * pos) , 8)); pos++; | ||
158 | returndic.Add("Land", rep.Substring((7 * pos) , 8)); pos++; | ||
159 | returndic.Add("Wind", rep.Substring((7 * pos) , 8)); pos++; | ||
160 | returndic.Add("Cloud", rep.Substring((7 * pos) , 8)); pos++; | ||
161 | returndic.Add("Task", rep.Substring((7 * pos) , 8)); pos++; | ||
162 | returndic.Add("Texture", rep.Substring((7 * pos), 8)); pos++; | ||
163 | returndic.Add("Asset", rep.Substring((7 * pos), 8)); | ||
164 | /* | ||
165 | * return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}", | ||
166 | SendQueue.Count(), | ||
167 | IncomingPacketQueue.Count, | ||
168 | OutgoingPacketQueue.Count, | ||
169 | ResendOutgoingPacketQueue.Count, | ||
170 | LandOutgoingPacketQueue.Count, | ||
171 | WindOutgoingPacketQueue.Count, | ||
172 | CloudOutgoingPacketQueue.Count, | ||
173 | TaskOutgoingPacketQueue.Count, | ||
174 | TextureOutgoingPacketQueue.Count, | ||
175 | AssetOutgoingPacketQueue.Count); | ||
176 | */ | ||
177 | } | ||
178 | |||
179 | |||
180 | |||
181 | return returndic; | ||
182 | } | ||
183 | #endregion | ||
184 | } | ||
185 | } | ||
diff --git a/OpenSim/Region/UserStatistics/Default_Report.cs b/OpenSim/Region/UserStatistics/Default_Report.cs new file mode 100644 index 0000000..02b15ad --- /dev/null +++ b/OpenSim/Region/UserStatistics/Default_Report.cs | |||
@@ -0,0 +1,215 @@ | |||
1 | using System; | ||
2 | using System.Collections; | ||
3 | using System.Collections.Generic; | ||
4 | using System.Reflection; | ||
5 | using System.Text; | ||
6 | using Mono.Data.SqliteClient; | ||
7 | using OpenMetaverse; | ||
8 | using OpenSim.Region.Environment.Scenes; | ||
9 | using OpenSim.Framework.Statistics; | ||
10 | |||
11 | |||
12 | namespace OpenSim.Region.UserStatistics | ||
13 | { | ||
14 | public class Default_Report : IStatsController | ||
15 | { | ||
16 | |||
17 | public Default_Report() | ||
18 | { | ||
19 | |||
20 | } | ||
21 | |||
22 | #region IStatsController Members | ||
23 | |||
24 | public Hashtable ProcessModel(Hashtable pParams) | ||
25 | { | ||
26 | SqliteConnection conn = (SqliteConnection)pParams["DatabaseConnection"]; | ||
27 | List<Scene> m_scene = (List<Scene>)pParams["Scenes"]; | ||
28 | |||
29 | stats_default_page_values mData = rep_DefaultReport_data(conn, m_scene); | ||
30 | mData.sim_stat_data = (Dictionary<UUID,USimStatsData>)pParams["SimStats"]; | ||
31 | |||
32 | Hashtable nh = new Hashtable(); | ||
33 | nh.Add("hdata", mData); | ||
34 | |||
35 | return nh; | ||
36 | } | ||
37 | |||
38 | public string RenderView(Hashtable pModelResult) | ||
39 | { | ||
40 | stats_default_page_values mData = (stats_default_page_values) pModelResult["hdata"]; | ||
41 | return rep_Default_report_view(mData); | ||
42 | } | ||
43 | |||
44 | #endregion | ||
45 | |||
46 | public string rep_Default_report_view(stats_default_page_values values) | ||
47 | { | ||
48 | |||
49 | StringBuilder output = new StringBuilder(); | ||
50 | |||
51 | |||
52 | |||
53 | const string TableClass = "defaultr"; | ||
54 | const string TRClass = "defaultr"; | ||
55 | const string TDHeaderClass = "header"; | ||
56 | const string TDDataClass = "content"; | ||
57 | //const string TDDataClassRight = "contentright"; | ||
58 | const string TDDataClassCenter = "contentcenter"; | ||
59 | |||
60 | const string STYLESHEET = | ||
61 | @" | ||
62 | <STYLE> | ||
63 | body | ||
64 | { | ||
65 | font-size:15px; font-family:Helvetica, Verdana; color:Black; | ||
66 | } | ||
67 | TABLE.defaultr { } | ||
68 | TR.defaultr { padding: 5px; } | ||
69 | TD.header { font-weight:bold; padding:5px; } | ||
70 | TD.content {} | ||
71 | TD.contentright { text-align: right; } | ||
72 | TD.contentcenter { text-align: center; } | ||
73 | TD.align_top { vertical-align: top; } | ||
74 | </STYLE> | ||
75 | "; | ||
76 | HTMLUtil.HtmlHeaders_O(ref output); | ||
77 | |||
78 | HTMLUtil.InsertProtoTypeAJAX(ref output); | ||
79 | string[] ajaxUpdaterDivs = new string[2]; | ||
80 | int[] ajaxUpdaterSeconds = new int[2]; | ||
81 | string[] ajaxUpdaterReportFragments = new string[2]; | ||
82 | |||
83 | ajaxUpdaterDivs[0] = "activeconnections"; | ||
84 | ajaxUpdaterSeconds[0] = 10; | ||
85 | ajaxUpdaterReportFragments[0] = "activeconnectionsajax.ajax"; | ||
86 | |||
87 | ajaxUpdaterDivs[1] = "activesimstats"; | ||
88 | ajaxUpdaterSeconds[1] = 20; | ||
89 | ajaxUpdaterReportFragments[1] = "simstatsajax.ajax"; | ||
90 | |||
91 | HTMLUtil.InsertPeriodicUpdaters(ref output, ajaxUpdaterDivs, ajaxUpdaterSeconds, ajaxUpdaterReportFragments); | ||
92 | |||
93 | output.Append(STYLESHEET); | ||
94 | HTMLUtil.HtmlHeaders_C(ref output); | ||
95 | |||
96 | HTMLUtil.TABLE_O(ref output, TableClass); | ||
97 | HTMLUtil.TR_O(ref output, TRClass); | ||
98 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
99 | output.Append("# Users Total"); | ||
100 | HTMLUtil.TD_C(ref output); | ||
101 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
102 | output.Append("# Sessions Total"); | ||
103 | HTMLUtil.TD_C(ref output); | ||
104 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
105 | output.Append("Avg Client FPS"); | ||
106 | HTMLUtil.TD_C(ref output); | ||
107 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
108 | output.Append("Avg Client Mem Use"); | ||
109 | HTMLUtil.TD_C(ref output); | ||
110 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
111 | output.Append("Avg Sim FPS"); | ||
112 | HTMLUtil.TD_C(ref output); | ||
113 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
114 | output.Append("Avg Ping"); | ||
115 | HTMLUtil.TD_C(ref output); | ||
116 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
117 | output.Append("KB Out Total"); | ||
118 | HTMLUtil.TD_C(ref output); | ||
119 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
120 | output.Append("KB In Total"); | ||
121 | HTMLUtil.TD_C(ref output); | ||
122 | HTMLUtil.TR_C(ref output); | ||
123 | HTMLUtil.TR_O(ref output, TRClass); | ||
124 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
125 | output.Append(values.total_num_users); | ||
126 | HTMLUtil.TD_C(ref output); | ||
127 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
128 | output.Append(values.total_num_sessions); | ||
129 | HTMLUtil.TD_C(ref output); | ||
130 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
131 | output.Append(values.avg_client_fps); | ||
132 | HTMLUtil.TD_C(ref output); | ||
133 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
134 | output.Append(values.avg_client_mem_use); | ||
135 | HTMLUtil.TD_C(ref output); | ||
136 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
137 | output.Append(values.avg_sim_fps); | ||
138 | HTMLUtil.TD_C(ref output); | ||
139 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
140 | output.Append(values.avg_ping); | ||
141 | HTMLUtil.TD_C(ref output); | ||
142 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
143 | output.Append(values.total_kb_out); | ||
144 | HTMLUtil.TD_C(ref output); | ||
145 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
146 | output.Append(values.total_kb_in); | ||
147 | HTMLUtil.TD_C(ref output); | ||
148 | HTMLUtil.TR_C(ref output); | ||
149 | HTMLUtil.TABLE_C(ref output); | ||
150 | |||
151 | HTMLUtil.HR(ref output, ""); | ||
152 | HTMLUtil.TABLE_O(ref output, ""); | ||
153 | HTMLUtil.TR_O(ref output, ""); | ||
154 | HTMLUtil.TD_O(ref output, "align_top"); | ||
155 | output.Append("<DIV id=\"activeconnections\">loading...</DIV>"); | ||
156 | HTMLUtil.TD_C(ref output); | ||
157 | HTMLUtil.TD_O(ref output, "align_top"); | ||
158 | output.Append("<DIV id=\"activesimstats\">loading...</DIV>"); | ||
159 | |||
160 | HTMLUtil.TD_C(ref output); | ||
161 | HTMLUtil.TR_C(ref output); | ||
162 | HTMLUtil.TABLE_C(ref output); | ||
163 | output.Append("</BODY></HTML>"); | ||
164 | // TODO: FIXME: template | ||
165 | return output.ToString(); | ||
166 | } | ||
167 | |||
168 | |||
169 | |||
170 | public stats_default_page_values rep_DefaultReport_data(SqliteConnection db, List<Scene> m_scene) | ||
171 | { | ||
172 | stats_default_page_values returnstruct = new stats_default_page_values(); | ||
173 | returnstruct.all_scenes = m_scene.ToArray(); | ||
174 | lock (db) | ||
175 | { | ||
176 | string SQL = @"SELECT COUNT(DISTINCT agent_id) as agents, COUNT(*) as sessions, AVG(avg_fps) as client_fps, | ||
177 | AVG(avg_sim_fps) as savg_sim_fps, AVG(avg_ping) as sav_ping, SUM(n_out_kb) as num_in_kb, | ||
178 | SUM(n_out_pk) as num_in_packets, SUM(n_in_kb) as num_out_kb, SUM(n_in_pk) as num_out_packets, AVG(mem_use) as sav_mem_use | ||
179 | FROM stats_session_data;"; | ||
180 | SqliteCommand cmd = new SqliteCommand(SQL, db); | ||
181 | SqliteDataReader sdr = cmd.ExecuteReader(); | ||
182 | if (sdr.HasRows) | ||
183 | { | ||
184 | sdr.Read(); | ||
185 | returnstruct.total_num_users = Convert.ToInt32(sdr["agents"]); | ||
186 | returnstruct.total_num_sessions = Convert.ToInt32(sdr["sessions"]); | ||
187 | returnstruct.avg_client_fps = Convert.ToSingle(sdr["client_fps"]); | ||
188 | returnstruct.avg_sim_fps = Convert.ToSingle(sdr["savg_sim_fps"]); | ||
189 | returnstruct.avg_ping = Convert.ToSingle(sdr["sav_ping"]); | ||
190 | returnstruct.total_kb_out = Convert.ToSingle(sdr["num_out_kb"]); | ||
191 | returnstruct.total_kb_in = Convert.ToSingle(sdr["num_in_kb"]); | ||
192 | returnstruct.avg_client_mem_use = Convert.ToSingle(sdr["sav_mem_use"]); | ||
193 | |||
194 | } | ||
195 | } | ||
196 | return returnstruct; | ||
197 | } | ||
198 | |||
199 | } | ||
200 | |||
201 | public struct stats_default_page_values | ||
202 | { | ||
203 | public int total_num_users; | ||
204 | public int total_num_sessions; | ||
205 | public float avg_client_fps; | ||
206 | public float avg_client_mem_use; | ||
207 | public float avg_sim_fps; | ||
208 | public float avg_ping; | ||
209 | public float total_kb_out; | ||
210 | public float total_kb_in; | ||
211 | public float avg_client_resends; | ||
212 | public Scene[] all_scenes; | ||
213 | public Dictionary<UUID, USimStatsData> sim_stat_data; | ||
214 | } | ||
215 | } | ||
diff --git a/OpenSim/Region/UserStatistics/HTMLUtil.cs b/OpenSim/Region/UserStatistics/HTMLUtil.cs new file mode 100644 index 0000000..ed8cc98 --- /dev/null +++ b/OpenSim/Region/UserStatistics/HTMLUtil.cs | |||
@@ -0,0 +1,185 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | |||
5 | namespace OpenSim.Region.UserStatistics | ||
6 | { | ||
7 | public static class HTMLUtil | ||
8 | { | ||
9 | |||
10 | public static void TR_O(ref StringBuilder o, string pclass) | ||
11 | { | ||
12 | o.Append("<tr"); | ||
13 | if (pclass.Length > 0) | ||
14 | { | ||
15 | GenericClass(ref o, pclass); | ||
16 | } | ||
17 | o.Append(">\n\t"); | ||
18 | } | ||
19 | public static void TR_C(ref StringBuilder o) | ||
20 | { | ||
21 | o.Append("</tr>\n"); | ||
22 | } | ||
23 | |||
24 | public static void TD_O(ref StringBuilder o, string pclass) | ||
25 | { | ||
26 | o.Append("<td"); | ||
27 | if (pclass.Length > 0) | ||
28 | { | ||
29 | GenericClass(ref o, pclass); | ||
30 | } | ||
31 | o.Append(">"); | ||
32 | } | ||
33 | public static void TD_C(ref StringBuilder o) | ||
34 | { | ||
35 | o.Append("</td>"); | ||
36 | } | ||
37 | public static void TABLE_O(ref StringBuilder o, string pclass) | ||
38 | { | ||
39 | o.Append("<table"); | ||
40 | if (pclass.Length > 0) | ||
41 | { | ||
42 | GenericClass(ref o, pclass); | ||
43 | } | ||
44 | o.Append(">\n\t"); | ||
45 | } | ||
46 | public static void TABLE_C(ref StringBuilder o) | ||
47 | { | ||
48 | o.Append("</table>\n"); | ||
49 | } | ||
50 | |||
51 | public static void BLOCKQUOTE_O(ref StringBuilder o, string pclass) | ||
52 | { | ||
53 | o.Append("<blockquote"); | ||
54 | if (pclass.Length > 0) | ||
55 | { | ||
56 | GenericClass(ref o, pclass); | ||
57 | } | ||
58 | o.Append(" />\n"); | ||
59 | } | ||
60 | |||
61 | public static void BLOCKQUOTE_C(ref StringBuilder o) | ||
62 | { | ||
63 | o.Append("</blockquote>\n"); | ||
64 | } | ||
65 | |||
66 | public static void BR(ref StringBuilder o) | ||
67 | { | ||
68 | o.Append("<br />\n"); | ||
69 | } | ||
70 | |||
71 | public static void HR(ref StringBuilder o, string pclass) | ||
72 | { | ||
73 | o.Append("<hr"); | ||
74 | if (pclass.Length > 0) | ||
75 | { | ||
76 | GenericClass(ref o, pclass); | ||
77 | } | ||
78 | o.Append(" />\n"); | ||
79 | } | ||
80 | |||
81 | public static void UL_O(ref StringBuilder o, string pclass) | ||
82 | { | ||
83 | o.Append("<ul"); | ||
84 | if (pclass.Length > 0) | ||
85 | { | ||
86 | GenericClass(ref o, pclass); | ||
87 | } | ||
88 | o.Append(" />\n"); | ||
89 | } | ||
90 | |||
91 | public static void UL_C(ref StringBuilder o) | ||
92 | { | ||
93 | o.Append("</ul>\n"); | ||
94 | } | ||
95 | |||
96 | public static void OL_O(ref StringBuilder o, string pclass) | ||
97 | { | ||
98 | o.Append("<ol"); | ||
99 | if (pclass.Length > 0) | ||
100 | { | ||
101 | GenericClass(ref o, pclass); | ||
102 | } | ||
103 | o.Append(" />\n"); | ||
104 | } | ||
105 | |||
106 | public static void OL_C(ref StringBuilder o) | ||
107 | { | ||
108 | o.Append("</ol>\n"); | ||
109 | } | ||
110 | |||
111 | public static void LI_O(ref StringBuilder o, string pclass) | ||
112 | { | ||
113 | o.Append("<li"); | ||
114 | if (pclass.Length > 0) | ||
115 | { | ||
116 | GenericClass(ref o, pclass); | ||
117 | } | ||
118 | o.Append(" />\n"); | ||
119 | } | ||
120 | |||
121 | public static void LI_C(ref StringBuilder o) | ||
122 | { | ||
123 | o.Append("</li>\n"); | ||
124 | } | ||
125 | |||
126 | public static void GenericClass(ref StringBuilder o, string pclass) | ||
127 | { | ||
128 | o.Append(" class=\""); | ||
129 | o.Append(pclass); | ||
130 | o.Append("\""); | ||
131 | } | ||
132 | |||
133 | public static void InsertProtoTypeAJAX(ref StringBuilder o) | ||
134 | { | ||
135 | o.Append("<script type=\"text/javascript\" src=\"prototype.js\"></script>\n"); | ||
136 | o.Append("<script type=\"text/javascript\" src=\"updater.js\"></script>\n"); | ||
137 | } | ||
138 | |||
139 | public static void InsertPeriodicUpdaters(ref StringBuilder o, string[] divID, int[] seconds, string[] reportfrag) | ||
140 | { | ||
141 | o.Append("<script type=\"text/javascript\">\n"); | ||
142 | o.Append( | ||
143 | @" | ||
144 | // <![CDATA[ | ||
145 | document.observe('dom:loaded', function() { | ||
146 | /* | ||
147 | first arg : div to update | ||
148 | second arg : interval to poll in seconds | ||
149 | third arg : file to get data | ||
150 | */ | ||
151 | "); | ||
152 | for (int i = 0; i < divID.Length; i++) | ||
153 | { | ||
154 | |||
155 | o.Append("new updater('"); | ||
156 | o.Append(divID[i]); | ||
157 | o.Append("', "); | ||
158 | o.Append(seconds[i]); | ||
159 | o.Append(", '"); | ||
160 | o.Append(reportfrag[i]); | ||
161 | o.Append("');\n"); | ||
162 | } | ||
163 | |||
164 | o.Append(@" | ||
165 | }); | ||
166 | // ]]> | ||
167 | </script>"); | ||
168 | |||
169 | } | ||
170 | |||
171 | public static void HtmlHeaders_O ( ref StringBuilder o) | ||
172 | { | ||
173 | o.Append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"); | ||
174 | o.Append("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"nl\">"); | ||
175 | o.Append("<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />"); | ||
176 | |||
177 | |||
178 | } | ||
179 | public static void HtmlHeaders_C ( ref StringBuilder o) | ||
180 | { | ||
181 | o.Append("</HEAD>"); | ||
182 | o.Append("<BODY>"); | ||
183 | } | ||
184 | } | ||
185 | } | ||
diff --git a/OpenSim/Region/UserStatistics/IStatsReport.cs b/OpenSim/Region/UserStatistics/IStatsReport.cs new file mode 100644 index 0000000..4295c82 --- /dev/null +++ b/OpenSim/Region/UserStatistics/IStatsReport.cs | |||
@@ -0,0 +1,10 @@ | |||
1 | using System.Collections; | ||
2 | |||
3 | namespace OpenSim.Region.UserStatistics | ||
4 | { | ||
5 | public interface IStatsController | ||
6 | { | ||
7 | Hashtable ProcessModel(Hashtable pParams); | ||
8 | string RenderView(Hashtable pModelResult); | ||
9 | } | ||
10 | } | ||
diff --git a/OpenSim/Region/UserStatistics/Prototype_distributor.cs b/OpenSim/Region/UserStatistics/Prototype_distributor.cs new file mode 100644 index 0000000..8a7a18f --- /dev/null +++ b/OpenSim/Region/UserStatistics/Prototype_distributor.cs | |||
@@ -0,0 +1,33 @@ | |||
1 | using System; | ||
2 | using System.IO; | ||
3 | using System.Collections; | ||
4 | using System.Collections.Generic; | ||
5 | using System.Text; | ||
6 | using OpenSim.Framework; | ||
7 | |||
8 | namespace OpenSim.Region.UserStatistics | ||
9 | { | ||
10 | public class Prototype_distributor : IStatsController | ||
11 | { | ||
12 | private string prototypejs=string.Empty; | ||
13 | |||
14 | |||
15 | public Hashtable ProcessModel(Hashtable pParams) | ||
16 | { | ||
17 | Hashtable pResult = new Hashtable(); | ||
18 | if (prototypejs.Length == 0) | ||
19 | { | ||
20 | StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/prototype.js", FileMode.Open)); | ||
21 | prototypejs = fs.ReadToEnd(); | ||
22 | } | ||
23 | pResult["js"] = prototypejs; | ||
24 | return pResult; | ||
25 | } | ||
26 | |||
27 | public string RenderView(Hashtable pModelResult) | ||
28 | { | ||
29 | return pModelResult["js"].ToString(); | ||
30 | } | ||
31 | |||
32 | } | ||
33 | } | ||
diff --git a/OpenSim/Region/UserStatistics/SimStatsAJAX.cs b/OpenSim/Region/UserStatistics/SimStatsAJAX.cs new file mode 100644 index 0000000..f6dd1d6 --- /dev/null +++ b/OpenSim/Region/UserStatistics/SimStatsAJAX.cs | |||
@@ -0,0 +1,190 @@ | |||
1 | using System; | ||
2 | using System.Collections; | ||
3 | using System.Collections.Generic; | ||
4 | using System.Reflection; | ||
5 | using System.Text; | ||
6 | using Mono.Data.SqliteClient; | ||
7 | using OpenMetaverse; | ||
8 | using OpenSim.Region.Environment.Scenes; | ||
9 | using OpenSim.Framework.Statistics; | ||
10 | |||
11 | namespace OpenSim.Region.UserStatistics | ||
12 | { | ||
13 | public class SimStatsAJAX : IStatsController | ||
14 | { | ||
15 | #region IStatsController Members | ||
16 | |||
17 | public Hashtable ProcessModel(Hashtable pParams) | ||
18 | { | ||
19 | List<Scene> m_scene = (List<Scene>)pParams["Scenes"]; | ||
20 | |||
21 | Hashtable nh = new Hashtable(); | ||
22 | nh.Add("hdata", m_scene); | ||
23 | nh.Add("simstats", pParams["SimStats"]); | ||
24 | |||
25 | return nh; | ||
26 | } | ||
27 | |||
28 | public string RenderView(Hashtable pModelResult) | ||
29 | { | ||
30 | StringBuilder output = new StringBuilder(); | ||
31 | List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"]; | ||
32 | Dictionary<UUID, USimStatsData> sdatadic = (Dictionary<UUID,USimStatsData>)pModelResult["simstats"]; | ||
33 | |||
34 | const string TableClass = "defaultr"; | ||
35 | const string TRClass = "defaultr"; | ||
36 | const string TDHeaderClass = "header"; | ||
37 | const string TDDataClass = "content"; | ||
38 | //const string TDDataClassRight = "contentright"; | ||
39 | const string TDDataClassCenter = "contentcenter"; | ||
40 | |||
41 | foreach (USimStatsData sdata in sdatadic.Values) | ||
42 | { | ||
43 | |||
44 | |||
45 | foreach (Scene sn in all_scenes) | ||
46 | { | ||
47 | if (sn.RegionInfo.RegionID == sdata.RegionId) | ||
48 | { | ||
49 | output.Append("<H2>"); | ||
50 | output.Append(sn.RegionInfo.RegionName); | ||
51 | output.Append("</H2>"); | ||
52 | } | ||
53 | } | ||
54 | HTMLUtil.TABLE_O(ref output, TableClass); | ||
55 | HTMLUtil.TR_O(ref output, TRClass); | ||
56 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
57 | output.Append("Dilatn"); | ||
58 | HTMLUtil.TD_C(ref output); | ||
59 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
60 | output.Append("SimFPS"); | ||
61 | HTMLUtil.TD_C(ref output); | ||
62 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
63 | output.Append("PhysFPS"); | ||
64 | HTMLUtil.TD_C(ref output); | ||
65 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
66 | output.Append("AgntUp"); | ||
67 | HTMLUtil.TD_C(ref output); | ||
68 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
69 | output.Append("RootAg"); | ||
70 | HTMLUtil.TD_C(ref output); | ||
71 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
72 | output.Append("ChldAg"); | ||
73 | HTMLUtil.TD_C(ref output); | ||
74 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
75 | output.Append("Prims"); | ||
76 | HTMLUtil.TD_C(ref output); | ||
77 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
78 | output.Append("ATvPrm"); | ||
79 | HTMLUtil.TD_C(ref output); | ||
80 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
81 | output.Append("AtvScr"); | ||
82 | HTMLUtil.TD_C(ref output); | ||
83 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
84 | output.Append("ScrLPS"); | ||
85 | HTMLUtil.TD_C(ref output); | ||
86 | HTMLUtil.TR_C(ref output); | ||
87 | HTMLUtil.TR_O(ref output, TRClass); | ||
88 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
89 | output.Append(sdata.TimeDilation); | ||
90 | HTMLUtil.TD_C(ref output); | ||
91 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
92 | output.Append(sdata.SimFps); | ||
93 | HTMLUtil.TD_C(ref output); | ||
94 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
95 | output.Append(sdata.PhysicsFps); | ||
96 | HTMLUtil.TD_C(ref output); | ||
97 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
98 | output.Append(sdata.AgentUpdates); | ||
99 | HTMLUtil.TD_C(ref output); | ||
100 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
101 | output.Append(sdata.RootAgents); | ||
102 | HTMLUtil.TD_C(ref output); | ||
103 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
104 | output.Append(sdata.ChildAgents); | ||
105 | HTMLUtil.TD_C(ref output); | ||
106 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
107 | output.Append(sdata.TotalPrims); | ||
108 | HTMLUtil.TD_C(ref output); | ||
109 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
110 | output.Append(sdata.ActivePrims); | ||
111 | HTMLUtil.TD_C(ref output); | ||
112 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
113 | output.Append(sdata.ActiveScripts); | ||
114 | HTMLUtil.TD_C(ref output); | ||
115 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
116 | output.Append(sdata.ScriptLinesPerSecond); | ||
117 | HTMLUtil.TD_C(ref output); | ||
118 | HTMLUtil.TR_C(ref output); | ||
119 | HTMLUtil.TR_O(ref output, TRClass); | ||
120 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
121 | output.Append("FrmMS"); | ||
122 | HTMLUtil.TD_C(ref output); | ||
123 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
124 | output.Append("AgtMS"); | ||
125 | HTMLUtil.TD_C(ref output); | ||
126 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
127 | output.Append("PhysMS"); | ||
128 | HTMLUtil.TD_C(ref output); | ||
129 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
130 | output.Append("OthrMS"); | ||
131 | HTMLUtil.TD_C(ref output); | ||
132 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
133 | output.Append("ScrLPS"); | ||
134 | HTMLUtil.TD_C(ref output); | ||
135 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
136 | output.Append("OutPPS"); | ||
137 | HTMLUtil.TD_C(ref output); | ||
138 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
139 | output.Append("InPPS"); | ||
140 | HTMLUtil.TD_C(ref output); | ||
141 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
142 | output.Append("NoAckKB"); | ||
143 | HTMLUtil.TD_C(ref output); | ||
144 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
145 | output.Append("PndDWN"); | ||
146 | HTMLUtil.TD_C(ref output); | ||
147 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
148 | output.Append("PndUP"); | ||
149 | HTMLUtil.TD_C(ref output); | ||
150 | HTMLUtil.TR_C(ref output); | ||
151 | HTMLUtil.TR_O(ref output, TRClass); | ||
152 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
153 | output.Append(sdata.TotalFrameTime); | ||
154 | HTMLUtil.TD_C(ref output); | ||
155 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
156 | output.Append(sdata.AgentFrameTime); | ||
157 | HTMLUtil.TD_C(ref output); | ||
158 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
159 | output.Append(sdata.PhysicsFrameTime); | ||
160 | HTMLUtil.TD_C(ref output); | ||
161 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
162 | output.Append(sdata.OtherFrameTime); | ||
163 | HTMLUtil.TD_C(ref output); | ||
164 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
165 | output.Append(sdata.ScriptLinesPerSecond); | ||
166 | HTMLUtil.TD_C(ref output); | ||
167 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
168 | output.Append(sdata.OutPacketsPerSecond); | ||
169 | HTMLUtil.TD_C(ref output); | ||
170 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
171 | output.Append(sdata.InPacketsPerSecond); | ||
172 | HTMLUtil.TD_C(ref output); | ||
173 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
174 | output.Append(sdata.UnackedBytes); | ||
175 | HTMLUtil.TD_C(ref output); | ||
176 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
177 | output.Append(sdata.PendingDownloads); | ||
178 | HTMLUtil.TD_C(ref output); | ||
179 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
180 | output.Append(sdata.PendingUploads); | ||
181 | HTMLUtil.TD_C(ref output); | ||
182 | HTMLUtil.TR_C(ref output); | ||
183 | HTMLUtil.TABLE_C(ref output); | ||
184 | } | ||
185 | return output.ToString(); | ||
186 | } | ||
187 | |||
188 | #endregion | ||
189 | } | ||
190 | } | ||
diff --git a/OpenSim/Region/UserStatistics/Updater_distributor.cs b/OpenSim/Region/UserStatistics/Updater_distributor.cs new file mode 100644 index 0000000..4d571fa --- /dev/null +++ b/OpenSim/Region/UserStatistics/Updater_distributor.cs | |||
@@ -0,0 +1,35 @@ | |||
1 | using System; | ||
2 | using System.IO; | ||
3 | using System.Collections; | ||
4 | using System.Collections.Generic; | ||
5 | using System.Text; | ||
6 | using OpenSim.Framework; | ||
7 | |||
8 | namespace OpenSim.Region.UserStatistics | ||
9 | { | ||
10 | public class Updater_distributor : IStatsController | ||
11 | { | ||
12 | private string updaterjs = string.Empty; | ||
13 | |||
14 | |||
15 | public Hashtable ProcessModel(Hashtable pParams) | ||
16 | { | ||
17 | Hashtable pResult = new Hashtable(); | ||
18 | if (updaterjs.Length == 0) | ||
19 | { | ||
20 | StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/updater.js", FileMode.Open)); | ||
21 | updaterjs = fs.ReadToEnd(); | ||
22 | fs.Close(); | ||
23 | fs.Dispose(); | ||
24 | } | ||
25 | pResult["js"] = updaterjs; | ||
26 | return pResult; | ||
27 | } | ||
28 | |||
29 | public string RenderView(Hashtable pModelResult) | ||
30 | { | ||
31 | return pModelResult["js"].ToString(); | ||
32 | } | ||
33 | |||
34 | } | ||
35 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/UserStatistics/WebStatsModule.cs b/OpenSim/Region/UserStatistics/WebStatsModule.cs new file mode 100644 index 0000000..4eb8cb7 --- /dev/null +++ b/OpenSim/Region/UserStatistics/WebStatsModule.cs | |||
@@ -0,0 +1,1083 @@ | |||
1 | using System; | ||
2 | using System.Collections; | ||
3 | using System.Collections.Generic; | ||
4 | using System.Net; // to be used for REST-->Grid shortly | ||
5 | using System.Reflection; | ||
6 | using log4net; | ||
7 | using Nini.Config; | ||
8 | using OpenMetaverse; | ||
9 | using OpenMetaverse.StructuredData; | ||
10 | using OpenSim.Framework; | ||
11 | using OpenSim.Framework.Servers; | ||
12 | using OpenSim.Region.Environment.Interfaces; | ||
13 | using OpenSim.Region.Environment.Scenes; | ||
14 | using Mono.Data.SqliteClient; | ||
15 | |||
16 | |||
17 | using Caps = OpenSim.Framework.Communications.Capabilities.Caps; | ||
18 | |||
19 | using OSD = OpenMetaverse.StructuredData.OSD; | ||
20 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
21 | |||
22 | namespace OpenSim.Region.UserStatistics | ||
23 | { | ||
24 | public class WebStatsModule : IRegionModule | ||
25 | { | ||
26 | private static readonly ILog m_log = | ||
27 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
28 | private static SqliteConnection dbConn; | ||
29 | private Dictionary<UUID, UserSessionID> m_sessions = new Dictionary<UUID, UserSessionID>(); | ||
30 | private List<Scene> m_scene = new List<Scene>(); | ||
31 | private Dictionary<string, IStatsController> reports = new Dictionary<string, IStatsController>(); | ||
32 | private Dictionary<UUID, USimStatsData> m_simstatsCounters = new Dictionary<UUID, USimStatsData>(); | ||
33 | private const int updateStatsMod = 6; | ||
34 | private volatile int concurrencyCounter = 0; | ||
35 | private bool enabled = false; | ||
36 | |||
37 | |||
38 | public virtual void Initialise(Scene scene, IConfigSource config) | ||
39 | { | ||
40 | IConfig cnfg; | ||
41 | try | ||
42 | { | ||
43 | cnfg = config.Configs["WebStats"]; | ||
44 | enabled = cnfg.GetBoolean("enabled", false); | ||
45 | |||
46 | } | ||
47 | catch (Exception) | ||
48 | { | ||
49 | enabled = false; | ||
50 | } | ||
51 | if (!enabled) | ||
52 | { | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | lock (m_scene) | ||
57 | { | ||
58 | if (m_scene.Count == 0) | ||
59 | { | ||
60 | IConfig startupConfig = config.Configs["Startup"]; | ||
61 | |||
62 | dbConn = new SqliteConnection("URI=file:LocalUserStatistics.db,version=3"); | ||
63 | dbConn.Open(); | ||
64 | CheckAndUpdateDatabase(dbConn); | ||
65 | |||
66 | Default_Report rep = new Default_Report(); | ||
67 | Prototype_distributor protodep = new Prototype_distributor(); | ||
68 | Updater_distributor updatedep = new Updater_distributor(); | ||
69 | ActiveConnectionsAJAX ajConnections = new ActiveConnectionsAJAX(); | ||
70 | SimStatsAJAX ajSimStats = new SimStatsAJAX(); | ||
71 | reports.Add("", rep); | ||
72 | reports.Add("index.aspx", rep); | ||
73 | reports.Add("prototype.js", protodep); | ||
74 | reports.Add("updater.js", updatedep); | ||
75 | reports.Add("activeconnectionsajax.ajax", ajConnections); | ||
76 | reports.Add("simstatsajax.ajax", ajSimStats); | ||
77 | |||
78 | scene.CommsManager.HttpServer.AddHTTPHandler("/SStats/", HandleStatsRequest); | ||
79 | |||
80 | |||
81 | } | ||
82 | m_scene.Add(scene); | ||
83 | m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID)); | ||
84 | scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket; | ||
85 | } | ||
86 | |||
87 | } | ||
88 | |||
89 | public void ReceiveClassicSimStatsPacket(SimStats stats) | ||
90 | { | ||
91 | if (!enabled) | ||
92 | { | ||
93 | return; | ||
94 | } | ||
95 | |||
96 | try | ||
97 | { | ||
98 | |||
99 | if (concurrencyCounter > 0) | ||
100 | return; | ||
101 | |||
102 | USimStatsData ss = m_simstatsCounters[stats.RegionUUID]; | ||
103 | |||
104 | if ((++ss.StatsCounter % updateStatsMod) == 0) | ||
105 | { | ||
106 | ss.ConsumeSimStats(stats); | ||
107 | } | ||
108 | } | ||
109 | catch (KeyNotFoundException) | ||
110 | { | ||
111 | |||
112 | } | ||
113 | } | ||
114 | |||
115 | public Hashtable HandleStatsRequest(Hashtable request) | ||
116 | { | ||
117 | Hashtable responsedata = new Hashtable(); | ||
118 | string regpath = request["uri"].ToString(); | ||
119 | int response_code = 404; | ||
120 | string contenttype = "text/html"; | ||
121 | |||
122 | string strOut = string.Empty; | ||
123 | |||
124 | regpath = regpath.Remove(0, 8); | ||
125 | if (reports.ContainsKey(regpath)) | ||
126 | { | ||
127 | IStatsController rep = reports[regpath]; | ||
128 | Hashtable repParams = new Hashtable(); | ||
129 | |||
130 | repParams["DatabaseConnection"] = dbConn; | ||
131 | repParams["Scenes"] = m_scene; | ||
132 | repParams["SimStats"] = m_simstatsCounters; | ||
133 | |||
134 | concurrencyCounter++; | ||
135 | |||
136 | strOut = rep.RenderView(rep.ProcessModel(repParams)); | ||
137 | |||
138 | if (regpath.EndsWith("js")) | ||
139 | { | ||
140 | contenttype = "text/javascript"; | ||
141 | } | ||
142 | |||
143 | concurrencyCounter--; | ||
144 | |||
145 | response_code = 200; | ||
146 | |||
147 | } | ||
148 | else | ||
149 | { | ||
150 | strOut = m_scene[0].CommsManager.HttpServer.GetHTTP404(""); | ||
151 | } | ||
152 | |||
153 | |||
154 | responsedata["int_response_code"] = response_code; | ||
155 | responsedata["content_type"] = contenttype; | ||
156 | responsedata["keepalive"] = false; | ||
157 | responsedata["str_response_string"] = strOut; | ||
158 | |||
159 | return responsedata; | ||
160 | } | ||
161 | |||
162 | |||
163 | |||
164 | public void CheckAndUpdateDatabase(SqliteConnection db) | ||
165 | { | ||
166 | lock (db) | ||
167 | { | ||
168 | // TODO: FIXME: implement stats migrations | ||
169 | const string SQL = @"SELECT * FROM migrations LIMIT 1"; | ||
170 | |||
171 | SqliteCommand cmd = new SqliteCommand(SQL, db); | ||
172 | |||
173 | try | ||
174 | { | ||
175 | cmd.ExecuteNonQuery(); | ||
176 | } | ||
177 | catch (SqliteSyntaxException) | ||
178 | { | ||
179 | CreateTables(db); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | } | ||
184 | |||
185 | public void CreateTables(SqliteConnection db) | ||
186 | { | ||
187 | SqliteCommand createcmd = new SqliteCommand(SQL_STATS_TABLE_CREATE, db); | ||
188 | createcmd.ExecuteNonQuery(); | ||
189 | |||
190 | createcmd.CommandText = SQL_MIGRA_TABLE_CREATE; | ||
191 | createcmd.ExecuteNonQuery(); | ||
192 | } | ||
193 | |||
194 | |||
195 | |||
196 | public virtual void PostInitialise() | ||
197 | { | ||
198 | if (!enabled) | ||
199 | { | ||
200 | return; | ||
201 | } | ||
202 | AddHandlers(); | ||
203 | } | ||
204 | |||
205 | public virtual void Close() | ||
206 | { | ||
207 | if (!enabled) | ||
208 | { | ||
209 | return; | ||
210 | } | ||
211 | dbConn.Close(); | ||
212 | dbConn.Dispose(); | ||
213 | } | ||
214 | |||
215 | public virtual string Name | ||
216 | { | ||
217 | get { return "ViewerStatsModule"; } | ||
218 | } | ||
219 | |||
220 | public bool IsSharedModule | ||
221 | { | ||
222 | get { return true; } | ||
223 | } | ||
224 | |||
225 | public void OnRegisterCaps(UUID agentID, Caps caps) | ||
226 | { | ||
227 | m_log.DebugFormat("[VC]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps); | ||
228 | string capsPath = "/CAPS/VS/" + UUID.Random(); | ||
229 | caps.RegisterHandler("ViewerStats", | ||
230 | new RestStreamHandler("POST", capsPath, | ||
231 | delegate(string request, string path, string param, | ||
232 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
233 | { | ||
234 | return ViewerStatsReport(request, path, param, | ||
235 | agentID, caps); | ||
236 | })); | ||
237 | } | ||
238 | |||
239 | public void OnDeRegisterCaps(UUID agentID, Caps caps) | ||
240 | { | ||
241 | |||
242 | } | ||
243 | |||
244 | protected virtual void AddHandlers() | ||
245 | { | ||
246 | lock (m_scene) | ||
247 | { | ||
248 | foreach (Scene scene in m_scene) | ||
249 | { | ||
250 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
251 | scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps; | ||
252 | scene.EventManager.OnClientClosed += OnClientClosed; | ||
253 | scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; | ||
254 | scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | |||
259 | public void OnMakeRootAgent(ScenePresence agent) | ||
260 | { | ||
261 | UUID regionUUID = GetRegionUUIDFromHandle(agent.RegionHandle); | ||
262 | |||
263 | lock (m_sessions) | ||
264 | { | ||
265 | if (!m_sessions.ContainsKey(agent.UUID)) | ||
266 | { | ||
267 | UserSessionData usd = UserSessionUtil.newUserSessionData(); | ||
268 | |||
269 | UserSessionID uid = new UserSessionID(); | ||
270 | uid.name_f = agent.Firstname; | ||
271 | uid.name_l = agent.Lastname; | ||
272 | uid.region_id = regionUUID; | ||
273 | uid.session_id = agent.ControllingClient.SessionId; | ||
274 | uid.session_data = usd; | ||
275 | |||
276 | m_sessions.Add(agent.UUID, uid); | ||
277 | } | ||
278 | else | ||
279 | { | ||
280 | UserSessionID uid = m_sessions[agent.UUID]; | ||
281 | uid.region_id = regionUUID; | ||
282 | uid.session_id = agent.ControllingClient.SessionId; | ||
283 | m_sessions[agent.UUID] = uid; | ||
284 | } | ||
285 | } | ||
286 | } | ||
287 | |||
288 | |||
289 | |||
290 | |||
291 | public void OnMakeChildAgent(ScenePresence agent) | ||
292 | { | ||
293 | lock (m_sessions) | ||
294 | { | ||
295 | if (m_sessions.ContainsKey(agent.UUID)) | ||
296 | { | ||
297 | if (m_sessions[agent.UUID].region_id == GetRegionUUIDFromHandle(agent.RegionHandle)) | ||
298 | { | ||
299 | m_sessions.Remove(agent.UUID); | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | } | ||
304 | |||
305 | |||
306 | public void OnClientClosed(UUID agentID) | ||
307 | { | ||
308 | lock (m_sessions) | ||
309 | { | ||
310 | if (m_sessions.ContainsKey(agentID)) | ||
311 | { | ||
312 | m_sessions.Remove(agentID); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | } | ||
317 | |||
318 | public UUID GetRegionUUIDFromHandle(ulong regionhandle) | ||
319 | { | ||
320 | lock (m_scene) | ||
321 | { | ||
322 | foreach (Scene scene in m_scene) | ||
323 | { | ||
324 | if (scene.RegionInfo.RegionHandle == regionhandle) | ||
325 | return scene.RegionInfo.RegionID; | ||
326 | } | ||
327 | } | ||
328 | return UUID.Zero; | ||
329 | } | ||
330 | /// <summary> | ||
331 | /// Callback for a viewerstats cap | ||
332 | /// </summary> | ||
333 | /// <param name="request"></param> | ||
334 | /// <param name="path"></param> | ||
335 | /// <param name="param"></param> | ||
336 | /// <param name="agentID"></param> | ||
337 | /// <param name="caps"></param> | ||
338 | /// <returns></returns> | ||
339 | public string ViewerStatsReport(string request, string path, string param, | ||
340 | UUID agentID, Caps caps) | ||
341 | { | ||
342 | m_log.Debug(request); | ||
343 | UserSessionID uid; | ||
344 | UserSessionData usd; | ||
345 | |||
346 | lock (m_sessions) | ||
347 | { | ||
348 | if (!m_sessions.ContainsKey(agentID)) | ||
349 | { | ||
350 | m_log.Warn("[VS]: no session for stat disclosure"); | ||
351 | return string.Empty; | ||
352 | } | ||
353 | uid = m_sessions[agentID]; | ||
354 | } | ||
355 | |||
356 | usd = uid.session_data; | ||
357 | |||
358 | OSD message = OSDParser.DeserializeLLSDXml(request); | ||
359 | if (message.Type != OSDType.Map) | ||
360 | return String.Empty; | ||
361 | |||
362 | OSDMap mmap = (OSDMap) message; | ||
363 | { | ||
364 | if (mmap["agent"].Type != OSDType.Map) | ||
365 | return String.Empty; | ||
366 | OSDMap agent_map = (OSDMap) mmap["agent"]; | ||
367 | usd.agent_id = agentID; | ||
368 | usd.name_f = uid.name_f; | ||
369 | usd.name_l = uid.name_l; | ||
370 | usd.region_id = uid.region_id; | ||
371 | usd.a_language = agent_map["language"].AsString(); | ||
372 | usd.mem_use = (float) agent_map["mem_use"].AsReal(); | ||
373 | usd.meters_traveled = (float) agent_map["meters_traveled"].AsReal(); | ||
374 | usd.regions_visited = agent_map["regions_visited"].AsInteger(); | ||
375 | usd.run_time = (float) agent_map["run_time"].AsReal(); | ||
376 | usd.start_time = (float) agent_map["start_time"].AsReal(); | ||
377 | usd.client_version = agent_map["version"].AsString(); | ||
378 | |||
379 | UserSessionUtil.UpdateMultiItems(ref usd, agent_map["agents_in_view"].AsInteger(), | ||
380 | (float) agent_map["ping"].AsReal(), | ||
381 | (float) agent_map["sim_fps"].AsReal(), | ||
382 | (float) agent_map["fps"].AsReal()); | ||
383 | |||
384 | if (mmap["downloads"].Type != OSDType.Map) | ||
385 | return String.Empty; | ||
386 | OSDMap downloads_map = (OSDMap) mmap["downloads"]; | ||
387 | usd.d_object_kb = (float) downloads_map["object_kbytes"].AsReal(); | ||
388 | usd.d_texture_kb = (float) downloads_map["texture_kbytes"].AsReal(); | ||
389 | usd.d_world_kb = (float) downloads_map["workd_kbytes"].AsReal(); | ||
390 | |||
391 | |||
392 | usd.session_id = mmap["session_id"].AsUUID(); | ||
393 | |||
394 | if (mmap["system"].Type != OSDType.Map) | ||
395 | return String.Empty; | ||
396 | OSDMap system_map = (OSDMap) mmap["system"]; | ||
397 | |||
398 | usd.s_cpu = system_map["cpu"].AsString(); | ||
399 | usd.s_gpu = system_map["gpu"].AsString(); | ||
400 | usd.s_os = system_map["os"].AsString(); | ||
401 | usd.s_ram = system_map["ram"].AsInteger(); | ||
402 | |||
403 | if (mmap["stats"].Type != OSDType.Map) | ||
404 | return String.Empty; | ||
405 | |||
406 | OSDMap stats_map = (OSDMap) mmap["stats"]; | ||
407 | { | ||
408 | if (mmap["failures"].Type != OSDType.Map) | ||
409 | return String.Empty; | ||
410 | OSDMap stats_failures = (OSDMap) stats_map["failures"]; | ||
411 | usd.f_dropped = stats_failures["dropped"].AsInteger(); | ||
412 | usd.f_failed_resends = stats_failures["failed_resends"].AsInteger(); | ||
413 | usd.f_invalid = stats_failures["invalid"].AsInteger(); | ||
414 | usd.f_resent = stats_failures["resent"].AsInteger(); | ||
415 | usd.f_send_packet = stats_failures["send_packet"].AsInteger(); | ||
416 | |||
417 | if (mmap["net"].Type != OSDType.Map) | ||
418 | return String.Empty; | ||
419 | OSDMap stats_net = (OSDMap) stats_map["net"]; | ||
420 | { | ||
421 | if (mmap["in"].Type != OSDType.Map) | ||
422 | return String.Empty; | ||
423 | |||
424 | OSDMap net_in = (OSDMap) stats_net["in"]; | ||
425 | usd.n_in_kb = (float) net_in["kbytes"].AsReal(); | ||
426 | usd.n_in_pk = net_in["packets"].AsInteger(); | ||
427 | |||
428 | if (mmap["out"].Type != OSDType.Map) | ||
429 | return String.Empty; | ||
430 | OSDMap net_out = (OSDMap) stats_net["out"]; | ||
431 | |||
432 | usd.n_out_kb = (float) net_out["kbytes"].AsReal(); | ||
433 | usd.n_out_pk = net_out["packets"].AsInteger(); | ||
434 | } | ||
435 | |||
436 | |||
437 | } | ||
438 | } | ||
439 | |||
440 | uid.session_data = usd; | ||
441 | m_sessions[agentID] = uid; | ||
442 | UpdateUserStats(uid, dbConn); | ||
443 | |||
444 | return String.Empty; | ||
445 | } | ||
446 | |||
447 | public void UpdateUserStats(UserSessionID uid, SqliteConnection db) | ||
448 | { | ||
449 | lock (db) | ||
450 | { | ||
451 | SqliteCommand updatecmd = new SqliteCommand(SQL_STATS_TABLE_UPDATE, db); | ||
452 | updatecmd.Parameters.Add(new SqliteParameter(":session_id", uid.session_data.session_id.ToString())); | ||
453 | updatecmd.Parameters.Add(new SqliteParameter(":agent_id", uid.session_data.agent_id.ToString())); | ||
454 | updatecmd.Parameters.Add(new SqliteParameter(":region_id", uid.session_data.region_id.ToString())); | ||
455 | updatecmd.Parameters.Add(new SqliteParameter(":last_updated", (int) uid.session_data.last_updated)); | ||
456 | updatecmd.Parameters.Add(new SqliteParameter(":remote_ip", uid.session_data.remote_ip)); | ||
457 | updatecmd.Parameters.Add(new SqliteParameter(":name_f", uid.session_data.name_f)); | ||
458 | updatecmd.Parameters.Add(new SqliteParameter(":name_l", uid.session_data.name_l)); | ||
459 | updatecmd.Parameters.Add(new SqliteParameter(":avg_agents_in_view", uid.session_data.avg_agents_in_view)); | ||
460 | updatecmd.Parameters.Add(new SqliteParameter(":min_agents_in_view", | ||
461 | (int) uid.session_data.min_agents_in_view)); | ||
462 | updatecmd.Parameters.Add(new SqliteParameter(":max_agents_in_view", | ||
463 | (int) uid.session_data.max_agents_in_view)); | ||
464 | updatecmd.Parameters.Add(new SqliteParameter(":mode_agents_in_view", | ||
465 | (int) uid.session_data.mode_agents_in_view)); | ||
466 | updatecmd.Parameters.Add(new SqliteParameter(":avg_fps", uid.session_data.avg_fps)); | ||
467 | updatecmd.Parameters.Add(new SqliteParameter(":min_fps", uid.session_data.min_fps)); | ||
468 | updatecmd.Parameters.Add(new SqliteParameter(":max_fps", uid.session_data.max_fps)); | ||
469 | updatecmd.Parameters.Add(new SqliteParameter(":mode_fps", uid.session_data.mode_fps)); | ||
470 | updatecmd.Parameters.Add(new SqliteParameter(":a_language", uid.session_data.a_language)); | ||
471 | updatecmd.Parameters.Add(new SqliteParameter(":mem_use", uid.session_data.mem_use)); | ||
472 | updatecmd.Parameters.Add(new SqliteParameter(":meters_traveled", uid.session_data.meters_traveled)); | ||
473 | updatecmd.Parameters.Add(new SqliteParameter(":avg_ping", uid.session_data.avg_ping)); | ||
474 | updatecmd.Parameters.Add(new SqliteParameter(":min_ping", uid.session_data.min_ping)); | ||
475 | updatecmd.Parameters.Add(new SqliteParameter(":max_ping", uid.session_data.max_ping)); | ||
476 | updatecmd.Parameters.Add(new SqliteParameter(":mode_ping", uid.session_data.mode_ping)); | ||
477 | updatecmd.Parameters.Add(new SqliteParameter(":regions_visited", uid.session_data.regions_visited)); | ||
478 | updatecmd.Parameters.Add(new SqliteParameter(":run_time", uid.session_data.run_time)); | ||
479 | updatecmd.Parameters.Add(new SqliteParameter(":avg_sim_fps", uid.session_data.avg_sim_fps)); | ||
480 | updatecmd.Parameters.Add(new SqliteParameter(":min_sim_fps", uid.session_data.min_sim_fps)); | ||
481 | updatecmd.Parameters.Add(new SqliteParameter(":max_sim_fps", uid.session_data.max_sim_fps)); | ||
482 | updatecmd.Parameters.Add(new SqliteParameter(":mode_sim_fps", uid.session_data.mode_sim_fps)); | ||
483 | updatecmd.Parameters.Add(new SqliteParameter(":start_time", uid.session_data.start_time)); | ||
484 | updatecmd.Parameters.Add(new SqliteParameter(":client_version", uid.session_data.client_version)); | ||
485 | updatecmd.Parameters.Add(new SqliteParameter(":s_cpu", uid.session_data.s_cpu)); | ||
486 | updatecmd.Parameters.Add(new SqliteParameter(":s_gpu", uid.session_data.s_gpu)); | ||
487 | updatecmd.Parameters.Add(new SqliteParameter(":s_os", uid.session_data.s_os)); | ||
488 | updatecmd.Parameters.Add(new SqliteParameter(":s_ram", uid.session_data.s_ram)); | ||
489 | updatecmd.Parameters.Add(new SqliteParameter(":d_object_kb", uid.session_data.d_object_kb)); | ||
490 | updatecmd.Parameters.Add(new SqliteParameter(":d_texture_kb", uid.session_data.d_texture_kb)); | ||
491 | updatecmd.Parameters.Add(new SqliteParameter(":d_world_kb", uid.session_data.d_world_kb)); | ||
492 | updatecmd.Parameters.Add(new SqliteParameter(":n_in_kb", uid.session_data.n_in_kb)); | ||
493 | updatecmd.Parameters.Add(new SqliteParameter(":n_in_pk", uid.session_data.n_in_pk)); | ||
494 | updatecmd.Parameters.Add(new SqliteParameter(":n_out_kb", uid.session_data.n_out_kb)); | ||
495 | updatecmd.Parameters.Add(new SqliteParameter(":n_out_pk", uid.session_data.n_out_pk)); | ||
496 | updatecmd.Parameters.Add(new SqliteParameter(":f_dropped", uid.session_data.f_dropped)); | ||
497 | updatecmd.Parameters.Add(new SqliteParameter(":f_failed_resends", uid.session_data.f_failed_resends)); | ||
498 | updatecmd.Parameters.Add(new SqliteParameter(":f_invalid", uid.session_data.f_invalid)); | ||
499 | |||
500 | updatecmd.Parameters.Add(new SqliteParameter(":f_off_circuit", uid.session_data.f_off_circuit)); | ||
501 | updatecmd.Parameters.Add(new SqliteParameter(":f_resent", uid.session_data.f_resent)); | ||
502 | updatecmd.Parameters.Add(new SqliteParameter(":f_send_packet", uid.session_data.f_send_packet)); | ||
503 | |||
504 | updatecmd.Parameters.Add(new SqliteParameter(":session_key", uid.session_data.session_id.ToString())); | ||
505 | updatecmd.Parameters.Add(new SqliteParameter(":agent_key", uid.session_data.agent_id.ToString())); | ||
506 | updatecmd.Parameters.Add(new SqliteParameter(":region_key", uid.session_data.region_id.ToString())); | ||
507 | m_log.Debug("UPDATE"); | ||
508 | |||
509 | int result = updatecmd.ExecuteNonQuery(); | ||
510 | |||
511 | if (result == 0) | ||
512 | { | ||
513 | m_log.Debug("INSERT"); | ||
514 | updatecmd.CommandText = SQL_STATS_TABLE_INSERT; | ||
515 | updatecmd.ExecuteNonQuery(); | ||
516 | } | ||
517 | } | ||
518 | |||
519 | } | ||
520 | |||
521 | #region SQL | ||
522 | private const string SQL_MIGRA_TABLE_CREATE = @"create table migrations(name varchar(100), version int)"; | ||
523 | |||
524 | private const string SQL_STATS_TABLE_CREATE = @"CREATE TABLE stats_session_data ( | ||
525 | session_id VARCHAR(36) NOT NULL PRIMARY KEY, | ||
526 | agent_id VARCHAR(36) NOT NULL DEFAULT '', | ||
527 | region_id VARCHAR(36) NOT NULL DEFAULT '', | ||
528 | last_updated INT NOT NULL DEFAULT '0', | ||
529 | remote_ip VARCHAR(16) NOT NULL DEFAULT '', | ||
530 | name_f VARCHAR(50) NOT NULL DEFAULT '', | ||
531 | name_l VARCHAR(50) NOT NULL DEFAULT '', | ||
532 | avg_agents_in_view FLOAT NOT NULL DEFAULT '0', | ||
533 | min_agents_in_view INT NOT NULL DEFAULT '0', | ||
534 | max_agents_in_view INT NOT NULL DEFAULT '0', | ||
535 | mode_agents_in_view INT NOT NULL DEFAULT '0', | ||
536 | avg_fps FLOAT NOT NULL DEFAULT '0', | ||
537 | min_fps FLOAT NOT NULL DEFAULT '0', | ||
538 | max_fps FLOAT NOT NULL DEFAULT '0', | ||
539 | mode_fps FLOAT NOT NULL DEFAULT '0', | ||
540 | a_language VARCHAR(25) NOT NULL DEFAULT '', | ||
541 | mem_use FLOAT NOT NULL DEFAULT '0', | ||
542 | meters_traveled FLOAT NOT NULL DEFAULT '0', | ||
543 | avg_ping FLOAT NOT NULL DEFAULT '0', | ||
544 | min_ping FLOAT NOT NULL DEFAULT '0', | ||
545 | max_ping FLOAT NOT NULL DEFAULT '0', | ||
546 | mode_ping FLOAT NOT NULL DEFAULT '0', | ||
547 | regions_visited INT NOT NULL DEFAULT '0', | ||
548 | run_time FLOAT NOT NULL DEFAULT '0', | ||
549 | avg_sim_fps FLOAT NOT NULL DEFAULT '0', | ||
550 | min_sim_fps FLOAT NOT NULL DEFAULT '0', | ||
551 | max_sim_fps FLOAT NOT NULL DEFAULT '0', | ||
552 | mode_sim_fps FLOAT NOT NULL DEFAULT '0', | ||
553 | start_time FLOAT NOT NULL DEFAULT '0', | ||
554 | client_version VARCHAR(255) NOT NULL DEFAULT '', | ||
555 | s_cpu VARCHAR(255) NOT NULL DEFAULT '', | ||
556 | s_gpu VARCHAR(255) NOT NULL DEFAULT '', | ||
557 | s_os VARCHAR(2255) NOT NULL DEFAULT '', | ||
558 | s_ram INT NOT NULL DEFAULT '0', | ||
559 | d_object_kb FLOAT NOT NULL DEFAULT '0', | ||
560 | d_texture_kb FLOAT NOT NULL DEFAULT '0', | ||
561 | d_world_kb FLOAT NOT NULL DEFAULT '0', | ||
562 | n_in_kb FLOAT NOT NULL DEFAULT '0', | ||
563 | n_in_pk INT NOT NULL DEFAULT '0', | ||
564 | n_out_kb FLOAT NOT NULL DEFAULT '0', | ||
565 | n_out_pk INT NOT NULL DEFAULT '0', | ||
566 | f_dropped INT NOT NULL DEFAULT '0', | ||
567 | f_failed_resends INT NOT NULL DEFAULT '0', | ||
568 | f_invalid INT NOT NULL DEFAULT '0', | ||
569 | f_off_circuit INT NOT NULL DEFAULT '0', | ||
570 | f_resent INT NOT NULL DEFAULT '0', | ||
571 | f_send_packet INT NOT NULL DEFAULT '0' | ||
572 | );"; | ||
573 | |||
574 | private const string SQL_STATS_TABLE_INSERT = @"INSERT INTO stats_session_data ( | ||
575 | session_id, agent_id, region_id, last_updated, remote_ip, name_f, name_l, avg_agents_in_view, min_agents_in_view, max_agents_in_view, | ||
576 | mode_agents_in_view, avg_fps, min_fps, max_fps, mode_fps, a_language, mem_use, meters_traveled, avg_ping, min_ping, max_ping, mode_ping, | ||
577 | regions_visited, run_time, avg_sim_fps, min_sim_fps, max_sim_fps, mode_sim_fps, start_time, client_version, s_cpu, s_gpu, s_os, s_ram, | ||
578 | d_object_kb, d_texture_kb, n_in_kb, n_in_pk, n_out_kb, n_out_pk, f_dropped, f_failed_resends, f_invalid, f_invalid, f_off_circuit, | ||
579 | f_resent, f_send_packet | ||
580 | ) | ||
581 | VALUES | ||
582 | ( | ||
583 | :session_id, :agent_id, :region_id, :last_updated, :remote_ip, :name_f, :name_l, :avg_agents_in_view, :min_agents_in_view, :max_agents_in_view, | ||
584 | :mode_agents_in_view, :avg_fps, :min_fps, :max_fps, :mode_fps, :a_language, :mem_use, :meters_traveled, :avg_ping, :min_ping, :max_ping, :mode_ping, | ||
585 | :regions_visited, :run_time, :avg_sim_fps, :min_sim_fps, :max_sim_fps, :mode_sim_fps, :start_time, :client_version, :s_cpu, :s_gpu, :s_os, :s_ram, | ||
586 | :d_object_kb, :d_texture_kb, :n_in_kb, :n_in_pk, :n_out_kb, :n_out_pk, :f_dropped, :f_failed_resends, :f_invalid, :f_invalid, :f_off_circuit, | ||
587 | :f_resent, :f_send_packet | ||
588 | ) | ||
589 | "; | ||
590 | |||
591 | private const string SQL_STATS_TABLE_UPDATE = @" | ||
592 | UPDATE stats_session_data | ||
593 | set session_id=:session_id, | ||
594 | agent_id=:agent_id, | ||
595 | region_id=:region_id, | ||
596 | last_updated=:last_updated, | ||
597 | remote_ip=:remote_ip, | ||
598 | name_f=:name_f, | ||
599 | name_l=:name_l, | ||
600 | avg_agents_in_view=:avg_agents_in_view, | ||
601 | min_agents_in_view=:min_agents_in_view, | ||
602 | max_agents_in_view=:max_agents_in_view, | ||
603 | mode_agents_in_view=:mode_agents_in_view, | ||
604 | avg_fps=:avg_fps, | ||
605 | min_fps=:min_fps, | ||
606 | max_fps=:max_fps, | ||
607 | mode_fps=:mode_fps, | ||
608 | a_language=:a_language, | ||
609 | mem_use=:mem_use, | ||
610 | meters_traveled=:meters_traveled, | ||
611 | avg_ping=:avg_ping, | ||
612 | min_ping=:min_ping, | ||
613 | max_ping=:max_ping, | ||
614 | mode_ping=:mode_ping, | ||
615 | regions_visited=:regions_visited, | ||
616 | run_time=:run_time, | ||
617 | avg_sim_fps=:avg_sim_fps, | ||
618 | min_sim_fps=:min_sim_fps, | ||
619 | max_sim_fps=:max_sim_fps, | ||
620 | mode_sim_fps=:mode_sim_fps, | ||
621 | start_time=:start_time, | ||
622 | client_version=:client_version, | ||
623 | s_cpu=:s_cpu, | ||
624 | s_gpu=:s_gpu, | ||
625 | s_os=:s_os, | ||
626 | s_ram=:s_ram, | ||
627 | d_object_kb=:d_object_kb, | ||
628 | d_texture_kb=:d_texture_kb, | ||
629 | d_world_kb=:d_world_kb, | ||
630 | n_in_kb=:n_in_kb, | ||
631 | n_in_pk=:n_in_pk, | ||
632 | n_out_kb=:n_out_kb, | ||
633 | n_out_pk=:n_out_pk, | ||
634 | f_dropped=:f_dropped, | ||
635 | f_failed_resends=:f_failed_resends, | ||
636 | f_invalid=:f_invalid, | ||
637 | f_off_circuit=:f_off_circuit, | ||
638 | f_resent=:f_resent, | ||
639 | f_send_packet=:f_send_packet | ||
640 | WHERE session_id=:session_key AND agent_id=:agent_key AND region_id=:region_key"; | ||
641 | #endregion | ||
642 | } | ||
643 | public static class UserSessionUtil | ||
644 | { | ||
645 | public static UserSessionData newUserSessionData() | ||
646 | { | ||
647 | UserSessionData obj = ZeroSession(new UserSessionData()); | ||
648 | return obj; | ||
649 | } | ||
650 | |||
651 | public static void UpdateMultiItems(ref UserSessionData s, int agents_in_view, float ping, float sim_fps, float fps) | ||
652 | { | ||
653 | // don't insert zero values here or it'll skew the statistics. | ||
654 | if (agents_in_view == 0 && fps == 0 && sim_fps == 0 && ping == 0) | ||
655 | return; | ||
656 | s._agents_in_view.Add(agents_in_view); | ||
657 | s._fps.Add(fps); | ||
658 | s._sim_fps.Add(sim_fps); | ||
659 | s._ping.Add(ping); | ||
660 | |||
661 | int[] __agents_in_view = s._agents_in_view.ToArray(); | ||
662 | |||
663 | s.avg_agents_in_view = ArrayAvg_i(__agents_in_view); | ||
664 | s.min_agents_in_view = ArrayMin_i(__agents_in_view); | ||
665 | s.max_agents_in_view = ArrayMax_i(__agents_in_view); | ||
666 | s.mode_agents_in_view = ArrayMode_i(__agents_in_view); | ||
667 | |||
668 | float[] __fps = s._fps.ToArray(); | ||
669 | s.avg_fps = ArrayAvg_f(__fps); | ||
670 | s.min_fps = ArrayMin_f(__fps); | ||
671 | s.max_fps = ArrayMax_f(__fps); | ||
672 | s.mode_fps = ArrayMode_f(__fps); | ||
673 | |||
674 | float[] __sim_fps = s._sim_fps.ToArray(); | ||
675 | s.avg_sim_fps = ArrayAvg_f(__sim_fps); | ||
676 | s.min_sim_fps = ArrayMin_f(__sim_fps); | ||
677 | s.max_sim_fps = ArrayMax_f(__sim_fps); | ||
678 | s.mode_sim_fps = ArrayMode_f(__sim_fps); | ||
679 | |||
680 | float[] __ping = s._ping.ToArray(); | ||
681 | s.avg_ping = ArrayAvg_f(__ping); | ||
682 | s.min_ping = ArrayMin_f(__ping); | ||
683 | s.max_ping = ArrayMax_f(__ping); | ||
684 | s.mode_ping = ArrayMode_f(__ping); | ||
685 | |||
686 | } | ||
687 | |||
688 | #region Statistics | ||
689 | |||
690 | public static int ArrayMin_i(int[] arr) | ||
691 | { | ||
692 | int cnt = arr.Length; | ||
693 | if (cnt == 0) | ||
694 | return 0; | ||
695 | |||
696 | Array.Sort(arr); | ||
697 | return arr[0]; | ||
698 | } | ||
699 | |||
700 | public static int ArrayMax_i(int[] arr) | ||
701 | { | ||
702 | int cnt = arr.Length; | ||
703 | if (cnt == 0) | ||
704 | return 0; | ||
705 | |||
706 | Array.Sort(arr); | ||
707 | return arr[cnt-1]; | ||
708 | } | ||
709 | |||
710 | public static float ArrayMin_f(float[] arr) | ||
711 | { | ||
712 | int cnt = arr.Length; | ||
713 | if (cnt == 0) | ||
714 | return 0; | ||
715 | |||
716 | Array.Sort(arr); | ||
717 | return arr[0]; | ||
718 | } | ||
719 | |||
720 | public static float ArrayMax_f(float[] arr) | ||
721 | { | ||
722 | int cnt = arr.Length; | ||
723 | if (cnt == 0) | ||
724 | return 0; | ||
725 | |||
726 | Array.Sort(arr); | ||
727 | return arr[cnt - 1]; | ||
728 | } | ||
729 | |||
730 | public static float ArrayAvg_i(int[] arr) | ||
731 | { | ||
732 | int cnt = arr.Length; | ||
733 | |||
734 | if (cnt == 0) | ||
735 | return 0; | ||
736 | |||
737 | float result = arr[0]; | ||
738 | |||
739 | for (int i = 1; i < cnt; i++) | ||
740 | result += arr[i]; | ||
741 | |||
742 | return result / cnt; | ||
743 | } | ||
744 | |||
745 | public static float ArrayAvg_f(float[] arr) | ||
746 | { | ||
747 | int cnt = arr.Length; | ||
748 | |||
749 | if (cnt == 0) | ||
750 | return 0; | ||
751 | |||
752 | float result = arr[0]; | ||
753 | |||
754 | for (int i = 1; i < cnt; i++) | ||
755 | result += arr[i]; | ||
756 | |||
757 | return result / cnt; | ||
758 | } | ||
759 | |||
760 | |||
761 | public static float ArrayMode_f(float[] arr) | ||
762 | { | ||
763 | List<float> mode = new List<float>(); | ||
764 | |||
765 | float[] srtArr = new float[arr.Length]; | ||
766 | float[,] freq = new float[arr.Length, 2]; | ||
767 | Array.Copy(arr, srtArr, arr.Length); | ||
768 | Array.Sort(srtArr); | ||
769 | |||
770 | float tmp = srtArr[0]; | ||
771 | int index = 0; | ||
772 | int i = 0; | ||
773 | while (i < srtArr.Length) | ||
774 | { | ||
775 | freq[index, 0] = tmp; | ||
776 | |||
777 | while (tmp == srtArr[i]) | ||
778 | { | ||
779 | freq[index, 1]++; | ||
780 | i++; | ||
781 | |||
782 | if (i > srtArr.Length - 1) | ||
783 | break; | ||
784 | } | ||
785 | |||
786 | if (i < srtArr.Length) | ||
787 | { | ||
788 | tmp = srtArr[i]; | ||
789 | index++; | ||
790 | } | ||
791 | |||
792 | } | ||
793 | |||
794 | Array.Clear(srtArr, 0, srtArr.Length); | ||
795 | |||
796 | for (i = 0; i < srtArr.Length; i++) | ||
797 | srtArr[i] = freq[i, 1]; | ||
798 | |||
799 | Array.Sort(srtArr); | ||
800 | |||
801 | if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1) | ||
802 | return 0; | ||
803 | |||
804 | float freqtest = (float)freq.Length / freq.Rank; | ||
805 | |||
806 | for (i = 0; i < freqtest; i++) | ||
807 | { | ||
808 | if (freq[i, 1] == srtArr[index]) | ||
809 | mode.Add(freq[i, 0]); | ||
810 | |||
811 | } | ||
812 | |||
813 | return mode.ToArray()[0]; | ||
814 | |||
815 | } | ||
816 | |||
817 | |||
818 | public static int ArrayMode_i(int[] arr) | ||
819 | { | ||
820 | List<int> mode = new List<int>(); | ||
821 | |||
822 | int[] srtArr = new int[arr.Length]; | ||
823 | int[,] freq = new int[arr.Length, 2]; | ||
824 | Array.Copy(arr, srtArr, arr.Length); | ||
825 | Array.Sort(srtArr); | ||
826 | |||
827 | int tmp = srtArr[0]; | ||
828 | int index = 0; | ||
829 | int i = 0; | ||
830 | while (i < srtArr.Length) | ||
831 | { | ||
832 | freq[index, 0] = tmp; | ||
833 | |||
834 | while (tmp == srtArr[i]) | ||
835 | { | ||
836 | freq[index, 1]++; | ||
837 | i++; | ||
838 | |||
839 | if (i > srtArr.Length - 1) | ||
840 | break; | ||
841 | } | ||
842 | |||
843 | if (i < srtArr.Length) | ||
844 | { | ||
845 | tmp = srtArr[i]; | ||
846 | index++; | ||
847 | } | ||
848 | |||
849 | } | ||
850 | |||
851 | Array.Clear(srtArr, 0, srtArr.Length); | ||
852 | |||
853 | for (i = 0; i < srtArr.Length; i++) | ||
854 | srtArr[i] = freq[i, 1]; | ||
855 | |||
856 | Array.Sort(srtArr); | ||
857 | |||
858 | if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1) | ||
859 | return 0; | ||
860 | |||
861 | float freqtest = (float)freq.Length / freq.Rank; | ||
862 | |||
863 | for (i = 0; i < freqtest; i++) | ||
864 | { | ||
865 | if (freq[i, 1] == srtArr[index]) | ||
866 | mode.Add(freq[i, 0]); | ||
867 | |||
868 | } | ||
869 | |||
870 | return mode.ToArray()[0]; | ||
871 | |||
872 | } | ||
873 | |||
874 | #endregion | ||
875 | |||
876 | private static UserSessionData ZeroSession(UserSessionData s) | ||
877 | { | ||
878 | s.session_id = UUID.Zero; | ||
879 | s.agent_id = UUID.Zero; | ||
880 | s.region_id = UUID.Zero; | ||
881 | s.last_updated = Util.UnixTimeSinceEpoch(); | ||
882 | s.remote_ip = ""; | ||
883 | s.name_f = ""; | ||
884 | s.name_l = ""; | ||
885 | s.avg_agents_in_view = 0; | ||
886 | s.min_agents_in_view = 0; | ||
887 | s.max_agents_in_view = 0; | ||
888 | s.mode_agents_in_view = 0; | ||
889 | s.avg_fps = 0; | ||
890 | s.min_fps = 0; | ||
891 | s.max_fps = 0; | ||
892 | s.mode_fps = 0; | ||
893 | s.a_language = ""; | ||
894 | s.mem_use = 0; | ||
895 | s.meters_traveled = 0; | ||
896 | s.avg_ping = 0; | ||
897 | s.min_ping = 0; | ||
898 | s.max_ping = 0; | ||
899 | s.mode_ping = 0; | ||
900 | s.regions_visited = 0; | ||
901 | s.run_time = 0; | ||
902 | s.avg_sim_fps = 0; | ||
903 | s.min_sim_fps = 0; | ||
904 | s.max_sim_fps = 0; | ||
905 | s.mode_sim_fps = 0; | ||
906 | s.start_time = 0; | ||
907 | s.client_version = ""; | ||
908 | s.s_cpu = ""; | ||
909 | s.s_gpu = ""; | ||
910 | s.s_os = ""; | ||
911 | s.s_ram = 0; | ||
912 | s.d_object_kb = 0; | ||
913 | s.d_texture_kb = 0; | ||
914 | s.d_world_kb = 0; | ||
915 | s.n_in_kb = 0; | ||
916 | s.n_in_pk = 0; | ||
917 | s.n_out_kb = 0; | ||
918 | s.n_out_pk = 0; | ||
919 | s.f_dropped = 0; | ||
920 | s.f_failed_resends = 0; | ||
921 | s.f_invalid = 0; | ||
922 | s.f_off_circuit = 0; | ||
923 | s.f_resent = 0; | ||
924 | s.f_send_packet = 0; | ||
925 | s._ping = new List<float>(); | ||
926 | s._fps = new List<float>(); | ||
927 | s._sim_fps = new List<float>(); | ||
928 | s._agents_in_view = new List<int>(); | ||
929 | return s; | ||
930 | } | ||
931 | } | ||
932 | #region structs | ||
933 | |||
934 | public struct UserSessionID | ||
935 | { | ||
936 | public UUID session_id; | ||
937 | public UUID region_id; | ||
938 | public string name_f; | ||
939 | public string name_l; | ||
940 | public UserSessionData session_data; | ||
941 | } | ||
942 | |||
943 | public struct UserSessionData | ||
944 | { | ||
945 | public UUID session_id; | ||
946 | public UUID agent_id; | ||
947 | public UUID region_id; | ||
948 | public float last_updated; | ||
949 | public string remote_ip; | ||
950 | public string name_f; | ||
951 | public string name_l; | ||
952 | public float avg_agents_in_view; | ||
953 | public float min_agents_in_view; | ||
954 | public float max_agents_in_view; | ||
955 | public float mode_agents_in_view; | ||
956 | public float avg_fps; | ||
957 | public float min_fps; | ||
958 | public float max_fps; | ||
959 | public float mode_fps; | ||
960 | public string a_language; | ||
961 | public float mem_use; | ||
962 | public float meters_traveled; | ||
963 | public float avg_ping; | ||
964 | public float min_ping; | ||
965 | public float max_ping; | ||
966 | public float mode_ping; | ||
967 | public int regions_visited; | ||
968 | public float run_time; | ||
969 | public float avg_sim_fps; | ||
970 | public float min_sim_fps; | ||
971 | public float max_sim_fps; | ||
972 | public float mode_sim_fps; | ||
973 | public float start_time; | ||
974 | public string client_version; | ||
975 | public string s_cpu; | ||
976 | public string s_gpu; | ||
977 | public string s_os; | ||
978 | public int s_ram; | ||
979 | public float d_object_kb; | ||
980 | public float d_texture_kb; | ||
981 | public float d_world_kb; | ||
982 | public float n_in_kb; | ||
983 | public int n_in_pk; | ||
984 | public float n_out_kb; | ||
985 | public int n_out_pk; | ||
986 | public int f_dropped; | ||
987 | public int f_failed_resends; | ||
988 | public int f_invalid; | ||
989 | public int f_off_circuit; | ||
990 | public int f_resent; | ||
991 | public int f_send_packet; | ||
992 | public List<float> _ping; | ||
993 | public List<float> _fps; | ||
994 | public List<float> _sim_fps; | ||
995 | public List<int> _agents_in_view; | ||
996 | } | ||
997 | |||
998 | |||
999 | #endregion | ||
1000 | |||
1001 | public class USimStatsData | ||
1002 | { | ||
1003 | private UUID m_regionID = UUID.Zero; | ||
1004 | private volatile int m_statcounter = 0; | ||
1005 | private volatile float m_timeDilation; | ||
1006 | private volatile float m_simFps; | ||
1007 | private volatile float m_physicsFps; | ||
1008 | private volatile float m_agentUpdates; | ||
1009 | private volatile float m_rootAgents; | ||
1010 | private volatile float m_childAgents; | ||
1011 | private volatile float m_totalPrims; | ||
1012 | private volatile float m_activePrims; | ||
1013 | private volatile float m_totalFrameTime; | ||
1014 | private volatile float m_netFrameTime; | ||
1015 | private volatile float m_physicsFrameTime; | ||
1016 | private volatile float m_otherFrameTime; | ||
1017 | private volatile float m_imageFrameTime; | ||
1018 | private volatile float m_inPacketsPerSecond; | ||
1019 | private volatile float m_outPacketsPerSecond; | ||
1020 | private volatile float m_unackedBytes; | ||
1021 | private volatile float m_agentFrameTime; | ||
1022 | private volatile float m_pendingDownloads; | ||
1023 | private volatile float m_pendingUploads; | ||
1024 | private volatile float m_activeScripts; | ||
1025 | private volatile float m_scriptLinesPerSecond; | ||
1026 | |||
1027 | public UUID RegionId { get { return m_regionID; } } | ||
1028 | public int StatsCounter { get { return m_statcounter; } set { m_statcounter = value;}} | ||
1029 | public float TimeDilation { get { return m_timeDilation; } } | ||
1030 | public float SimFps { get { return m_simFps; } } | ||
1031 | public float PhysicsFps { get { return m_physicsFps; } } | ||
1032 | public float AgentUpdates { get { return m_agentUpdates; } } | ||
1033 | public float RootAgents { get { return m_rootAgents; } } | ||
1034 | public float ChildAgents { get { return m_childAgents; } } | ||
1035 | public float TotalPrims { get { return m_totalPrims; } } | ||
1036 | public float ActivePrims { get { return m_activePrims; } } | ||
1037 | public float TotalFrameTime { get { return m_totalFrameTime; } } | ||
1038 | public float NetFrameTime { get { return m_netFrameTime; } } | ||
1039 | public float PhysicsFrameTime { get { return m_physicsFrameTime; } } | ||
1040 | public float OtherFrameTime { get { return m_otherFrameTime; } } | ||
1041 | public float ImageFrameTime { get { return m_imageFrameTime; } } | ||
1042 | public float InPacketsPerSecond { get { return m_inPacketsPerSecond; } } | ||
1043 | public float OutPacketsPerSecond { get { return m_outPacketsPerSecond; } } | ||
1044 | public float UnackedBytes { get { return m_unackedBytes; } } | ||
1045 | public float AgentFrameTime { get { return m_agentFrameTime; } } | ||
1046 | public float PendingDownloads { get { return m_pendingDownloads; } } | ||
1047 | public float PendingUploads { get { return m_pendingUploads; } } | ||
1048 | public float ActiveScripts { get { return m_activeScripts; } } | ||
1049 | public float ScriptLinesPerSecond { get { return m_scriptLinesPerSecond; } } | ||
1050 | |||
1051 | public USimStatsData(UUID pRegionID) | ||
1052 | { | ||
1053 | m_regionID = pRegionID; | ||
1054 | } | ||
1055 | |||
1056 | public void ConsumeSimStats(SimStats stats) | ||
1057 | { | ||
1058 | m_regionID = stats.RegionUUID; | ||
1059 | m_timeDilation = stats.StatsBlock[0].StatValue; | ||
1060 | m_simFps = stats.StatsBlock[1].StatValue; | ||
1061 | m_physicsFps = stats.StatsBlock[2].StatValue; | ||
1062 | m_agentUpdates = stats.StatsBlock[3].StatValue; | ||
1063 | m_rootAgents = stats.StatsBlock[4].StatValue; | ||
1064 | m_childAgents = stats.StatsBlock[5].StatValue; | ||
1065 | m_totalPrims = stats.StatsBlock[6].StatValue; | ||
1066 | m_activePrims = stats.StatsBlock[7].StatValue; | ||
1067 | m_totalFrameTime = stats.StatsBlock[8].StatValue; | ||
1068 | m_netFrameTime = stats.StatsBlock[9].StatValue; | ||
1069 | m_physicsFrameTime = stats.StatsBlock[10].StatValue; | ||
1070 | m_otherFrameTime = stats.StatsBlock[11].StatValue; | ||
1071 | m_imageFrameTime = stats.StatsBlock[12].StatValue; | ||
1072 | m_inPacketsPerSecond = stats.StatsBlock[13].StatValue; | ||
1073 | m_outPacketsPerSecond = stats.StatsBlock[14].StatValue; | ||
1074 | m_unackedBytes = stats.StatsBlock[15].StatValue; | ||
1075 | m_agentFrameTime = stats.StatsBlock[16].StatValue; | ||
1076 | m_pendingDownloads = stats.StatsBlock[17].StatValue; | ||
1077 | m_pendingUploads = stats.StatsBlock[18].StatValue; | ||
1078 | m_activeScripts = stats.StatsBlock[19].StatValue; | ||
1079 | m_scriptLinesPerSecond = stats.StatsBlock[20].StatValue; | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1083 | } | ||