aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/UserStatistics/WebStatsModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/UserStatistics/WebStatsModule.cs')
-rw-r--r--OpenSim/Region/UserStatistics/WebStatsModule.cs1183
1 files changed, 0 insertions, 1183 deletions
diff --git a/OpenSim/Region/UserStatistics/WebStatsModule.cs b/OpenSim/Region/UserStatistics/WebStatsModule.cs
deleted file mode 100644
index 64cb577..0000000
--- a/OpenSim/Region/UserStatistics/WebStatsModule.cs
+++ /dev/null
@@ -1,1183 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Net; // to be used for REST-->Grid shortly
33using System.Reflection;
34using System.Text;
35using System.Threading;
36using log4net;
37using Nini.Config;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45using Mono.Data.SqliteClient;
46using Mono.Addins;
47
48using Caps = OpenSim.Framework.Capabilities.Caps;
49
50using OSD = OpenMetaverse.StructuredData.OSD;
51using OSDMap = OpenMetaverse.StructuredData.OSDMap;
52
53[assembly: Addin("WebStats", "1.0")]
54[assembly: AddinDependency("OpenSim", "0.5")]
55
56namespace OpenSim.Region.UserStatistics
57{
58 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebStatsModule")]
59 public class WebStatsModule : ISharedRegionModule
60 {
61 private static readonly ILog m_log =
62 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63
64 private static SqliteConnection dbConn;
65
66 /// <summary>
67 /// User statistics sessions keyed by agent ID
68 /// </summary>
69 private Dictionary<UUID, UserSession> m_sessions = new Dictionary<UUID, UserSession>();
70
71 private List<Scene> m_scenes = new List<Scene>();
72 private Dictionary<string, IStatsController> reports = new Dictionary<string, IStatsController>();
73 private Dictionary<UUID, USimStatsData> m_simstatsCounters = new Dictionary<UUID, USimStatsData>();
74 private const int updateStatsMod = 6;
75 private int updateLogMod = 1;
76 private volatile int updateLogCounter = 0;
77 private volatile int concurrencyCounter = 0;
78 private bool enabled = false;
79 private string m_loglines = String.Empty;
80 private volatile int lastHit = 12000;
81
82 #region ISharedRegionModule
83
84 public virtual void Initialise(IConfigSource config)
85 {
86 IConfig cnfg = config.Configs["WebStats"];
87
88 if (cnfg != null)
89 enabled = cnfg.GetBoolean("enabled", false);
90 }
91
92 public virtual void PostInitialise()
93 {
94 if (!enabled)
95 return;
96
97 if (Util.IsWindows())
98 Util.LoadArchSpecificWindowsDll("sqlite3.dll");
99
100 //IConfig startupConfig = config.Configs["Startup"];
101
102 dbConn = new SqliteConnection("URI=file:LocalUserStatistics.db,version=3");
103 dbConn.Open();
104 CreateTables(dbConn);
105
106 Prototype_distributor protodep = new Prototype_distributor();
107 Updater_distributor updatedep = new Updater_distributor();
108 ActiveConnectionsAJAX ajConnections = new ActiveConnectionsAJAX();
109 SimStatsAJAX ajSimStats = new SimStatsAJAX();
110 LogLinesAJAX ajLogLines = new LogLinesAJAX();
111 Default_Report defaultReport = new Default_Report();
112 Clients_report clientReport = new Clients_report();
113 Sessions_Report sessionsReport = new Sessions_Report();
114
115 reports.Add("prototype.js", protodep);
116 reports.Add("updater.js", updatedep);
117 reports.Add("activeconnectionsajax.html", ajConnections);
118 reports.Add("simstatsajax.html", ajSimStats);
119 reports.Add("activelogajax.html", ajLogLines);
120 reports.Add("default.report", defaultReport);
121 reports.Add("clients.report", clientReport);
122 reports.Add("sessions.report", sessionsReport);
123
124 ////
125 // Add Your own Reports here (Do Not Modify Lines here Devs!)
126 ////
127
128 ////
129 // End Own reports section
130 ////
131
132 MainServer.Instance.AddHTTPHandler("/SStats/", HandleStatsRequest);
133 MainServer.Instance.AddHTTPHandler("/CAPS/VS/", HandleUnknownCAPSRequest);
134 }
135
136 public virtual void AddRegion(Scene scene)
137 {
138 if (!enabled)
139 return;
140
141 lock (m_scenes)
142 {
143 m_scenes.Add(scene);
144 updateLogMod = m_scenes.Count * 2;
145
146 m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID));
147
148 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
149 scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps;
150 scene.EventManager.OnClientClosed += OnClientClosed;
151 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
152 scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket;
153 }
154 }
155
156 public void RegionLoaded(Scene scene)
157 {
158 }
159
160 public void RemoveRegion(Scene scene)
161 {
162 if (!enabled)
163 return;
164
165 lock (m_scenes)
166 {
167 m_scenes.Remove(scene);
168 updateLogMod = m_scenes.Count * 2;
169 m_simstatsCounters.Remove(scene.RegionInfo.RegionID);
170 }
171 }
172
173 public virtual void Close()
174 {
175 if (!enabled)
176 return;
177
178 dbConn.Close();
179 dbConn.Dispose();
180 m_sessions.Clear();
181 m_scenes.Clear();
182 reports.Clear();
183 m_simstatsCounters.Clear();
184 }
185
186 public virtual string Name
187 {
188 get { return "ViewerStatsModule"; }
189 }
190
191 public Type ReplaceableInterface
192 {
193 get { return null; }
194 }
195
196 #endregion
197
198 private void ReceiveClassicSimStatsPacket(SimStats stats)
199 {
200 if (!enabled)
201 return;
202
203 try
204 {
205 // Ignore the update if there's a report running right now
206 // ignore the update if there hasn't been a hit in 30 seconds.
207 if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000)
208 return;
209
210 // We will conduct this under lock so that fields such as updateLogCounter do not potentially get
211 // confused if a scene is removed.
212 // XXX: Possibly the scope of this lock could be reduced though it's not critical.
213 lock (m_scenes)
214 {
215 if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0)
216 {
217 m_loglines = readLogLines(10);
218
219 if (updateLogCounter > 10000)
220 updateLogCounter = 1;
221 }
222
223 USimStatsData ss = m_simstatsCounters[stats.RegionUUID];
224
225 if ((++ss.StatsCounter % updateStatsMod) == 0)
226 {
227 ss.ConsumeSimStats(stats);
228 }
229 }
230 }
231 catch (KeyNotFoundException)
232 {
233 }
234 }
235
236 private Hashtable HandleUnknownCAPSRequest(Hashtable request)
237 {
238 //string regpath = request["uri"].ToString();
239 int response_code = 200;
240 string contenttype = "text/html";
241 UpdateUserStats(ParseViewerStats(request["body"].ToString(), UUID.Zero), dbConn);
242 Hashtable responsedata = new Hashtable();
243
244 responsedata["int_response_code"] = response_code;
245 responsedata["content_type"] = contenttype;
246 responsedata["keepalive"] = false;
247 responsedata["str_response_string"] = string.Empty;
248 return responsedata;
249 }
250
251 private Hashtable HandleStatsRequest(Hashtable request)
252 {
253 lastHit = System.Environment.TickCount;
254 Hashtable responsedata = new Hashtable();
255 string regpath = request["uri"].ToString();
256 int response_code = 404;
257 string contenttype = "text/html";
258
259 string strOut = string.Empty;
260
261 regpath = regpath.Remove(0, 8);
262 if (regpath.Length == 0) regpath = "default.report";
263 if (reports.ContainsKey(regpath))
264 {
265 IStatsController rep = reports[regpath];
266 Hashtable repParams = new Hashtable();
267
268 if (request.ContainsKey("requestvars"))
269 repParams["RequestVars"] = request["requestvars"];
270 else
271 repParams["RequestVars"] = new Hashtable();
272
273 if (request.ContainsKey("querystringkeys"))
274 repParams["QueryStringKeys"] = request["querystringkeys"];
275 else
276 repParams["QueryStringKeys"] = new string[0];
277
278
279 repParams["DatabaseConnection"] = dbConn;
280 repParams["Scenes"] = m_scenes;
281 repParams["SimStats"] = m_simstatsCounters;
282 repParams["LogLines"] = m_loglines;
283 repParams["Reports"] = reports;
284
285 concurrencyCounter++;
286
287 strOut = rep.RenderView(rep.ProcessModel(repParams));
288
289 if (regpath.EndsWith("js"))
290 {
291 contenttype = "text/javascript";
292 }
293
294 concurrencyCounter--;
295
296 response_code = 200;
297 }
298 else
299 {
300 strOut = MainServer.Instance.GetHTTP404("");
301 }
302
303 responsedata["int_response_code"] = response_code;
304 responsedata["content_type"] = contenttype;
305 responsedata["keepalive"] = false;
306 responsedata["str_response_string"] = strOut;
307
308 return responsedata;
309 }
310
311 private void CreateTables(SqliteConnection db)
312 {
313 using (SqliteCommand createcmd = new SqliteCommand(SQL_STATS_TABLE_CREATE, db))
314 {
315 createcmd.ExecuteNonQuery();
316 }
317 }
318
319 private void OnRegisterCaps(UUID agentID, Caps caps)
320 {
321// m_log.DebugFormat("[WEB STATS MODULE]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
322
323 string capsPath = "/CAPS/VS/" + UUID.Random();
324 caps.RegisterHandler(
325 "ViewerStats",
326 new RestStreamHandler(
327 "POST",
328 capsPath,
329 (request, path, param, httpRequest, httpResponse)
330 => ViewerStatsReport(request, path, param, agentID, caps),
331 "ViewerStats",
332 agentID.ToString()));
333 }
334
335 private void OnDeRegisterCaps(UUID agentID, Caps caps)
336 {
337 }
338
339 protected virtual void AddEventHandlers()
340 {
341 lock (m_scenes)
342 {
343 updateLogMod = m_scenes.Count * 2;
344 foreach (Scene scene in m_scenes)
345 {
346 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
347 scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps;
348 scene.EventManager.OnClientClosed += OnClientClosed;
349 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
350 }
351 }
352 }
353
354 private void OnMakeRootAgent(ScenePresence agent)
355 {
356// m_log.DebugFormat(
357// "[WEB STATS MODULE]: Looking for session {0} for {1} in {2}",
358// agent.ControllingClient.SessionId, agent.Name, agent.Scene.Name);
359
360 lock (m_sessions)
361 {
362 UserSession uid;
363
364 if (!m_sessions.ContainsKey(agent.UUID))
365 {
366 UserSessionData usd = UserSessionUtil.newUserSessionData();
367 uid = new UserSession();
368 uid.name_f = agent.Firstname;
369 uid.name_l = agent.Lastname;
370 uid.session_data = usd;
371
372 m_sessions.Add(agent.UUID, uid);
373 }
374 else
375 {
376 uid = m_sessions[agent.UUID];
377 }
378
379 uid.region_id = agent.Scene.RegionInfo.RegionID;
380 uid.session_id = agent.ControllingClient.SessionId;
381 }
382 }
383
384 private void OnClientClosed(UUID agentID, Scene scene)
385 {
386 lock (m_sessions)
387 {
388 if (m_sessions.ContainsKey(agentID) && m_sessions[agentID].region_id == scene.RegionInfo.RegionID)
389 {
390 m_sessions.Remove(agentID);
391 }
392 }
393 }
394
395 private string readLogLines(int amount)
396 {
397 Encoding encoding = Encoding.ASCII;
398 int sizeOfChar = encoding.GetByteCount("\n");
399 byte[] buffer = encoding.GetBytes("\n");
400 string logfile = Util.logDir() + "/" + "OpenSim.log";
401 FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
402 Int64 tokenCount = 0;
403 Int64 endPosition = fs.Length / sizeOfChar;
404
405 for (Int64 position = sizeOfChar; position < endPosition; position += sizeOfChar)
406 {
407 fs.Seek(-position, SeekOrigin.End);
408 fs.Read(buffer, 0, buffer.Length);
409
410 if (encoding.GetString(buffer) == "\n")
411 {
412 tokenCount++;
413 if (tokenCount == amount)
414 {
415 byte[] returnBuffer = new byte[fs.Length - fs.Position];
416 fs.Read(returnBuffer, 0, returnBuffer.Length);
417 fs.Close();
418 fs.Dispose();
419 return encoding.GetString(returnBuffer);
420 }
421 }
422 }
423
424 // handle case where number of tokens in file is less than numberOfTokens
425 fs.Seek(0, SeekOrigin.Begin);
426 buffer = new byte[fs.Length];
427 fs.Read(buffer, 0, buffer.Length);
428 fs.Close();
429 fs.Dispose();
430 return encoding.GetString(buffer);
431 }
432
433 /// <summary>
434 /// Callback for a viewerstats cap
435 /// </summary>
436 /// <param name="request"></param>
437 /// <param name="path"></param>
438 /// <param name="param"></param>
439 /// <param name="agentID"></param>
440 /// <param name="caps"></param>
441 /// <returns></returns>
442 private string ViewerStatsReport(string request, string path, string param,
443 UUID agentID, Caps caps)
444 {
445// m_log.DebugFormat("[WEB STATS MODULE]: Received viewer starts report from {0}", agentID);
446
447 UpdateUserStats(ParseViewerStats(request, agentID), dbConn);
448
449 return String.Empty;
450 }
451
452 private UserSession ParseViewerStats(string request, UUID agentID)
453 {
454 UserSession uid = new UserSession();
455 UserSessionData usd;
456 OSD message = OSDParser.DeserializeLLSDXml(request);
457 OSDMap mmap;
458
459 lock (m_sessions)
460 {
461 if (agentID != UUID.Zero)
462 {
463 if (!m_sessions.ContainsKey(agentID))
464 {
465 m_log.WarnFormat("[WEB STATS MODULE]: no session for stat disclosure for agent {0}", agentID);
466 return new UserSession();
467 }
468
469 uid = m_sessions[agentID];
470
471// m_log.DebugFormat("[WEB STATS MODULE]: Got session {0} for {1}", uid.session_id, agentID);
472 }
473 else
474 {
475 // parse through the beginning to locate the session
476 if (message.Type != OSDType.Map)
477 return new UserSession();
478
479 mmap = (OSDMap)message;
480 {
481 UUID sessionID = mmap["session_id"].AsUUID();
482
483 if (sessionID == UUID.Zero)
484 return new UserSession();
485
486
487 // search through each session looking for the owner
488 foreach (UUID usersessionid in m_sessions.Keys)
489 {
490 // got it!
491 if (m_sessions[usersessionid].session_id == sessionID)
492 {
493 agentID = usersessionid;
494 uid = m_sessions[usersessionid];
495 break;
496 }
497
498 }
499
500 // can't find a session
501 if (agentID == UUID.Zero)
502 {
503 return new UserSession();
504 }
505 }
506 }
507 }
508
509 usd = uid.session_data;
510
511 if (message.Type != OSDType.Map)
512 return new UserSession();
513
514 mmap = (OSDMap)message;
515 {
516 if (mmap["agent"].Type != OSDType.Map)
517 return new UserSession();
518 OSDMap agent_map = (OSDMap)mmap["agent"];
519 usd.agent_id = agentID;
520 usd.name_f = uid.name_f;
521 usd.name_l = uid.name_l;
522 usd.region_id = uid.region_id;
523 usd.a_language = agent_map["language"].AsString();
524 usd.mem_use = (float)agent_map["mem_use"].AsReal();
525 usd.meters_traveled = (float)agent_map["meters_traveled"].AsReal();
526 usd.regions_visited = agent_map["regions_visited"].AsInteger();
527 usd.run_time = (float)agent_map["run_time"].AsReal();
528 usd.start_time = (float)agent_map["start_time"].AsReal();
529 usd.client_version = agent_map["version"].AsString();
530
531 UserSessionUtil.UpdateMultiItems(ref usd, agent_map["agents_in_view"].AsInteger(),
532 (float)agent_map["ping"].AsReal(),
533 (float)agent_map["sim_fps"].AsReal(),
534 (float)agent_map["fps"].AsReal());
535
536 if (mmap["downloads"].Type != OSDType.Map)
537 return new UserSession();
538 OSDMap downloads_map = (OSDMap)mmap["downloads"];
539 usd.d_object_kb = (float)downloads_map["object_kbytes"].AsReal();
540 usd.d_texture_kb = (float)downloads_map["texture_kbytes"].AsReal();
541 usd.d_world_kb = (float)downloads_map["workd_kbytes"].AsReal();
542
543// m_log.DebugFormat("[WEB STATS MODULE]: mmap[\"session_id\"] = [{0}]", mmap["session_id"].AsUUID());
544
545 usd.session_id = mmap["session_id"].AsUUID();
546
547 if (mmap["system"].Type != OSDType.Map)
548 return new UserSession();
549 OSDMap system_map = (OSDMap)mmap["system"];
550
551 usd.s_cpu = system_map["cpu"].AsString();
552 usd.s_gpu = system_map["gpu"].AsString();
553 usd.s_os = system_map["os"].AsString();
554 usd.s_ram = system_map["ram"].AsInteger();
555
556 if (mmap["stats"].Type != OSDType.Map)
557 return new UserSession();
558
559 OSDMap stats_map = (OSDMap)mmap["stats"];
560 {
561
562 if (stats_map["failures"].Type != OSDType.Map)
563 return new UserSession();
564 OSDMap stats_failures = (OSDMap)stats_map["failures"];
565 usd.f_dropped = stats_failures["dropped"].AsInteger();
566 usd.f_failed_resends = stats_failures["failed_resends"].AsInteger();
567 usd.f_invalid = stats_failures["invalid"].AsInteger();
568 usd.f_resent = stats_failures["resent"].AsInteger();
569 usd.f_send_packet = stats_failures["send_packet"].AsInteger();
570
571 if (stats_map["net"].Type != OSDType.Map)
572 return new UserSession();
573 OSDMap stats_net = (OSDMap)stats_map["net"];
574 {
575 if (stats_net["in"].Type != OSDType.Map)
576 return new UserSession();
577
578 OSDMap net_in = (OSDMap)stats_net["in"];
579 usd.n_in_kb = (float)net_in["kbytes"].AsReal();
580 usd.n_in_pk = net_in["packets"].AsInteger();
581
582 if (stats_net["out"].Type != OSDType.Map)
583 return new UserSession();
584 OSDMap net_out = (OSDMap)stats_net["out"];
585
586 usd.n_out_kb = (float)net_out["kbytes"].AsReal();
587 usd.n_out_pk = net_out["packets"].AsInteger();
588 }
589 }
590 }
591
592 uid.session_data = usd;
593 m_sessions[agentID] = uid;
594
595// m_log.DebugFormat(
596// "[WEB STATS MODULE]: Parse data for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id);
597
598 return uid;
599 }
600
601 private void UpdateUserStats(UserSession uid, SqliteConnection db)
602 {
603// m_log.DebugFormat(
604// "[WEB STATS MODULE]: Updating user stats for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id);
605
606 if (uid.session_id == UUID.Zero)
607 return;
608
609 lock (db)
610 {
611 using (SqliteCommand updatecmd = new SqliteCommand(SQL_STATS_TABLE_INSERT, db))
612 {
613 updatecmd.Parameters.Add(new SqliteParameter(":session_id", uid.session_data.session_id.ToString()));
614 updatecmd.Parameters.Add(new SqliteParameter(":agent_id", uid.session_data.agent_id.ToString()));
615 updatecmd.Parameters.Add(new SqliteParameter(":region_id", uid.session_data.region_id.ToString()));
616 updatecmd.Parameters.Add(new SqliteParameter(":last_updated", (int) uid.session_data.last_updated));
617 updatecmd.Parameters.Add(new SqliteParameter(":remote_ip", uid.session_data.remote_ip));
618 updatecmd.Parameters.Add(new SqliteParameter(":name_f", uid.session_data.name_f));
619 updatecmd.Parameters.Add(new SqliteParameter(":name_l", uid.session_data.name_l));
620 updatecmd.Parameters.Add(new SqliteParameter(":avg_agents_in_view", uid.session_data.avg_agents_in_view));
621 updatecmd.Parameters.Add(new SqliteParameter(":min_agents_in_view",
622 (int) uid.session_data.min_agents_in_view));
623 updatecmd.Parameters.Add(new SqliteParameter(":max_agents_in_view",
624 (int) uid.session_data.max_agents_in_view));
625 updatecmd.Parameters.Add(new SqliteParameter(":mode_agents_in_view",
626 (int) uid.session_data.mode_agents_in_view));
627 updatecmd.Parameters.Add(new SqliteParameter(":avg_fps", uid.session_data.avg_fps));
628 updatecmd.Parameters.Add(new SqliteParameter(":min_fps", uid.session_data.min_fps));
629 updatecmd.Parameters.Add(new SqliteParameter(":max_fps", uid.session_data.max_fps));
630 updatecmd.Parameters.Add(new SqliteParameter(":mode_fps", uid.session_data.mode_fps));
631 updatecmd.Parameters.Add(new SqliteParameter(":a_language", uid.session_data.a_language));
632 updatecmd.Parameters.Add(new SqliteParameter(":mem_use", uid.session_data.mem_use));
633 updatecmd.Parameters.Add(new SqliteParameter(":meters_traveled", uid.session_data.meters_traveled));
634 updatecmd.Parameters.Add(new SqliteParameter(":avg_ping", uid.session_data.avg_ping));
635 updatecmd.Parameters.Add(new SqliteParameter(":min_ping", uid.session_data.min_ping));
636 updatecmd.Parameters.Add(new SqliteParameter(":max_ping", uid.session_data.max_ping));
637 updatecmd.Parameters.Add(new SqliteParameter(":mode_ping", uid.session_data.mode_ping));
638 updatecmd.Parameters.Add(new SqliteParameter(":regions_visited", uid.session_data.regions_visited));
639 updatecmd.Parameters.Add(new SqliteParameter(":run_time", uid.session_data.run_time));
640 updatecmd.Parameters.Add(new SqliteParameter(":avg_sim_fps", uid.session_data.avg_sim_fps));
641 updatecmd.Parameters.Add(new SqliteParameter(":min_sim_fps", uid.session_data.min_sim_fps));
642 updatecmd.Parameters.Add(new SqliteParameter(":max_sim_fps", uid.session_data.max_sim_fps));
643 updatecmd.Parameters.Add(new SqliteParameter(":mode_sim_fps", uid.session_data.mode_sim_fps));
644 updatecmd.Parameters.Add(new SqliteParameter(":start_time", uid.session_data.start_time));
645 updatecmd.Parameters.Add(new SqliteParameter(":client_version", uid.session_data.client_version));
646 updatecmd.Parameters.Add(new SqliteParameter(":s_cpu", uid.session_data.s_cpu));
647 updatecmd.Parameters.Add(new SqliteParameter(":s_gpu", uid.session_data.s_gpu));
648 updatecmd.Parameters.Add(new SqliteParameter(":s_os", uid.session_data.s_os));
649 updatecmd.Parameters.Add(new SqliteParameter(":s_ram", uid.session_data.s_ram));
650 updatecmd.Parameters.Add(new SqliteParameter(":d_object_kb", uid.session_data.d_object_kb));
651 updatecmd.Parameters.Add(new SqliteParameter(":d_texture_kb", uid.session_data.d_texture_kb));
652 updatecmd.Parameters.Add(new SqliteParameter(":d_world_kb", uid.session_data.d_world_kb));
653 updatecmd.Parameters.Add(new SqliteParameter(":n_in_kb", uid.session_data.n_in_kb));
654 updatecmd.Parameters.Add(new SqliteParameter(":n_in_pk", uid.session_data.n_in_pk));
655 updatecmd.Parameters.Add(new SqliteParameter(":n_out_kb", uid.session_data.n_out_kb));
656 updatecmd.Parameters.Add(new SqliteParameter(":n_out_pk", uid.session_data.n_out_pk));
657 updatecmd.Parameters.Add(new SqliteParameter(":f_dropped", uid.session_data.f_dropped));
658 updatecmd.Parameters.Add(new SqliteParameter(":f_failed_resends", uid.session_data.f_failed_resends));
659 updatecmd.Parameters.Add(new SqliteParameter(":f_invalid", uid.session_data.f_invalid));
660 updatecmd.Parameters.Add(new SqliteParameter(":f_off_circuit", uid.session_data.f_off_circuit));
661 updatecmd.Parameters.Add(new SqliteParameter(":f_resent", uid.session_data.f_resent));
662 updatecmd.Parameters.Add(new SqliteParameter(":f_send_packet", uid.session_data.f_send_packet));
663
664// StringBuilder parameters = new StringBuilder();
665// SqliteParameterCollection spc = updatecmd.Parameters;
666// foreach (SqliteParameter sp in spc)
667// parameters.AppendFormat("{0}={1},", sp.ParameterName, sp.Value);
668//
669// m_log.DebugFormat("[WEB STATS MODULE]: Parameters {0}", parameters);
670
671// m_log.DebugFormat("[WEB STATS MODULE]: Database stats update for {0}", uid.session_data.agent_id);
672
673 updatecmd.ExecuteNonQuery();
674 }
675 }
676 }
677
678 #region SQL
679 private const string SQL_STATS_TABLE_CREATE = @"CREATE TABLE IF NOT EXISTS stats_session_data (
680 session_id VARCHAR(36) NOT NULL PRIMARY KEY,
681 agent_id VARCHAR(36) NOT NULL DEFAULT '',
682 region_id VARCHAR(36) NOT NULL DEFAULT '',
683 last_updated INT NOT NULL DEFAULT '0',
684 remote_ip VARCHAR(16) NOT NULL DEFAULT '',
685 name_f VARCHAR(50) NOT NULL DEFAULT '',
686 name_l VARCHAR(50) NOT NULL DEFAULT '',
687 avg_agents_in_view FLOAT NOT NULL DEFAULT '0',
688 min_agents_in_view INT NOT NULL DEFAULT '0',
689 max_agents_in_view INT NOT NULL DEFAULT '0',
690 mode_agents_in_view INT NOT NULL DEFAULT '0',
691 avg_fps FLOAT NOT NULL DEFAULT '0',
692 min_fps FLOAT NOT NULL DEFAULT '0',
693 max_fps FLOAT NOT NULL DEFAULT '0',
694 mode_fps FLOAT NOT NULL DEFAULT '0',
695 a_language VARCHAR(25) NOT NULL DEFAULT '',
696 mem_use FLOAT NOT NULL DEFAULT '0',
697 meters_traveled FLOAT NOT NULL DEFAULT '0',
698 avg_ping FLOAT NOT NULL DEFAULT '0',
699 min_ping FLOAT NOT NULL DEFAULT '0',
700 max_ping FLOAT NOT NULL DEFAULT '0',
701 mode_ping FLOAT NOT NULL DEFAULT '0',
702 regions_visited INT NOT NULL DEFAULT '0',
703 run_time FLOAT NOT NULL DEFAULT '0',
704 avg_sim_fps FLOAT NOT NULL DEFAULT '0',
705 min_sim_fps FLOAT NOT NULL DEFAULT '0',
706 max_sim_fps FLOAT NOT NULL DEFAULT '0',
707 mode_sim_fps FLOAT NOT NULL DEFAULT '0',
708 start_time FLOAT NOT NULL DEFAULT '0',
709 client_version VARCHAR(255) NOT NULL DEFAULT '',
710 s_cpu VARCHAR(255) NOT NULL DEFAULT '',
711 s_gpu VARCHAR(255) NOT NULL DEFAULT '',
712 s_os VARCHAR(2255) NOT NULL DEFAULT '',
713 s_ram INT NOT NULL DEFAULT '0',
714 d_object_kb FLOAT NOT NULL DEFAULT '0',
715 d_texture_kb FLOAT NOT NULL DEFAULT '0',
716 d_world_kb FLOAT NOT NULL DEFAULT '0',
717 n_in_kb FLOAT NOT NULL DEFAULT '0',
718 n_in_pk INT NOT NULL DEFAULT '0',
719 n_out_kb FLOAT NOT NULL DEFAULT '0',
720 n_out_pk INT NOT NULL DEFAULT '0',
721 f_dropped INT NOT NULL DEFAULT '0',
722 f_failed_resends INT NOT NULL DEFAULT '0',
723 f_invalid INT NOT NULL DEFAULT '0',
724 f_off_circuit INT NOT NULL DEFAULT '0',
725 f_resent INT NOT NULL DEFAULT '0',
726 f_send_packet INT NOT NULL DEFAULT '0'
727 );";
728
729 private const string SQL_STATS_TABLE_INSERT = @"INSERT OR REPLACE INTO stats_session_data (
730session_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,
731mode_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,
732regions_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,
733d_object_kb, d_texture_kb, d_world_kb, n_in_kb, n_in_pk, n_out_kb, n_out_pk, f_dropped, f_failed_resends, f_invalid, f_off_circuit,
734f_resent, f_send_packet
735)
736VALUES
737(
738: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,
739: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,
740: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,
741:d_object_kb, :d_texture_kb, :d_world_kb, :n_in_kb, :n_in_pk, :n_out_kb, :n_out_pk, :f_dropped, :f_failed_resends, :f_invalid, :f_off_circuit,
742:f_resent, :f_send_packet
743)
744";
745
746 #endregion
747
748 }
749
750 public static class UserSessionUtil
751 {
752 public static UserSessionData newUserSessionData()
753 {
754 UserSessionData obj = ZeroSession(new UserSessionData());
755 return obj;
756 }
757
758 public static void UpdateMultiItems(ref UserSessionData s, int agents_in_view, float ping, float sim_fps, float fps)
759 {
760 // don't insert zero values here or it'll skew the statistics.
761 if (agents_in_view == 0 && fps == 0 && sim_fps == 0 && ping == 0)
762 return;
763 s._agents_in_view.Add(agents_in_view);
764 s._fps.Add(fps);
765 s._sim_fps.Add(sim_fps);
766 s._ping.Add(ping);
767
768 int[] __agents_in_view = s._agents_in_view.ToArray();
769
770 s.avg_agents_in_view = ArrayAvg_i(__agents_in_view);
771 s.min_agents_in_view = ArrayMin_i(__agents_in_view);
772 s.max_agents_in_view = ArrayMax_i(__agents_in_view);
773 s.mode_agents_in_view = ArrayMode_i(__agents_in_view);
774
775 float[] __fps = s._fps.ToArray();
776 s.avg_fps = ArrayAvg_f(__fps);
777 s.min_fps = ArrayMin_f(__fps);
778 s.max_fps = ArrayMax_f(__fps);
779 s.mode_fps = ArrayMode_f(__fps);
780
781 float[] __sim_fps = s._sim_fps.ToArray();
782 s.avg_sim_fps = ArrayAvg_f(__sim_fps);
783 s.min_sim_fps = ArrayMin_f(__sim_fps);
784 s.max_sim_fps = ArrayMax_f(__sim_fps);
785 s.mode_sim_fps = ArrayMode_f(__sim_fps);
786
787 float[] __ping = s._ping.ToArray();
788 s.avg_ping = ArrayAvg_f(__ping);
789 s.min_ping = ArrayMin_f(__ping);
790 s.max_ping = ArrayMax_f(__ping);
791 s.mode_ping = ArrayMode_f(__ping);
792 }
793
794 #region Statistics
795
796 public static int ArrayMin_i(int[] arr)
797 {
798 int cnt = arr.Length;
799 if (cnt == 0)
800 return 0;
801
802 Array.Sort(arr);
803 return arr[0];
804 }
805
806 public static int ArrayMax_i(int[] arr)
807 {
808 int cnt = arr.Length;
809 if (cnt == 0)
810 return 0;
811
812 Array.Sort(arr);
813 return arr[cnt-1];
814 }
815
816 public static float ArrayMin_f(float[] arr)
817 {
818 int cnt = arr.Length;
819 if (cnt == 0)
820 return 0;
821
822 Array.Sort(arr);
823 return arr[0];
824 }
825
826 public static float ArrayMax_f(float[] arr)
827 {
828 int cnt = arr.Length;
829 if (cnt == 0)
830 return 0;
831
832 Array.Sort(arr);
833 return arr[cnt - 1];
834 }
835
836 public static float ArrayAvg_i(int[] arr)
837 {
838 int cnt = arr.Length;
839
840 if (cnt == 0)
841 return 0;
842
843 float result = arr[0];
844
845 for (int i = 1; i < cnt; i++)
846 result += arr[i];
847
848 return result / cnt;
849 }
850
851 public static float ArrayAvg_f(float[] arr)
852 {
853 int cnt = arr.Length;
854
855 if (cnt == 0)
856 return 0;
857
858 float result = arr[0];
859
860 for (int i = 1; i < cnt; i++)
861 result += arr[i];
862
863 return result / cnt;
864 }
865
866 public static float ArrayMode_f(float[] arr)
867 {
868 List<float> mode = new List<float>();
869
870 float[] srtArr = new float[arr.Length];
871 float[,] freq = new float[arr.Length, 2];
872 Array.Copy(arr, srtArr, arr.Length);
873 Array.Sort(srtArr);
874
875 float tmp = srtArr[0];
876 int index = 0;
877 int i = 0;
878 while (i < srtArr.Length)
879 {
880 freq[index, 0] = tmp;
881
882 while (tmp == srtArr[i])
883 {
884 freq[index, 1]++;
885 i++;
886
887 if (i > srtArr.Length - 1)
888 break;
889 }
890
891 if (i < srtArr.Length)
892 {
893 tmp = srtArr[i];
894 index++;
895 }
896
897 }
898
899 Array.Clear(srtArr, 0, srtArr.Length);
900
901 for (i = 0; i < srtArr.Length; i++)
902 srtArr[i] = freq[i, 1];
903
904 Array.Sort(srtArr);
905
906 if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1)
907 return 0;
908
909 float freqtest = (float)freq.Length / freq.Rank;
910
911 for (i = 0; i < freqtest; i++)
912 {
913 if (freq[i, 1] == srtArr[index])
914 mode.Add(freq[i, 0]);
915
916 }
917
918 return mode.ToArray()[0];
919 }
920
921 public static int ArrayMode_i(int[] arr)
922 {
923 List<int> mode = new List<int>();
924
925 int[] srtArr = new int[arr.Length];
926 int[,] freq = new int[arr.Length, 2];
927 Array.Copy(arr, srtArr, arr.Length);
928 Array.Sort(srtArr);
929
930 int tmp = srtArr[0];
931 int index = 0;
932 int i = 0;
933 while (i < srtArr.Length)
934 {
935 freq[index, 0] = tmp;
936
937 while (tmp == srtArr[i])
938 {
939 freq[index, 1]++;
940 i++;
941
942 if (i > srtArr.Length - 1)
943 break;
944 }
945
946 if (i < srtArr.Length)
947 {
948 tmp = srtArr[i];
949 index++;
950 }
951
952 }
953
954 Array.Clear(srtArr, 0, srtArr.Length);
955
956 for (i = 0; i < srtArr.Length; i++)
957 srtArr[i] = freq[i, 1];
958
959 Array.Sort(srtArr);
960
961 if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1)
962 return 0;
963
964 float freqtest = (float)freq.Length / freq.Rank;
965
966 for (i = 0; i < freqtest; i++)
967 {
968 if (freq[i, 1] == srtArr[index])
969 mode.Add(freq[i, 0]);
970
971 }
972
973 return mode.ToArray()[0];
974 }
975
976 #endregion
977
978 private static UserSessionData ZeroSession(UserSessionData s)
979 {
980 s.session_id = UUID.Zero;
981 s.agent_id = UUID.Zero;
982 s.region_id = UUID.Zero;
983 s.last_updated = Util.UnixTimeSinceEpoch();
984 s.remote_ip = "";
985 s.name_f = "";
986 s.name_l = "";
987 s.avg_agents_in_view = 0;
988 s.min_agents_in_view = 0;
989 s.max_agents_in_view = 0;
990 s.mode_agents_in_view = 0;
991 s.avg_fps = 0;
992 s.min_fps = 0;
993 s.max_fps = 0;
994 s.mode_fps = 0;
995 s.a_language = "";
996 s.mem_use = 0;
997 s.meters_traveled = 0;
998 s.avg_ping = 0;
999 s.min_ping = 0;
1000 s.max_ping = 0;
1001 s.mode_ping = 0;
1002 s.regions_visited = 0;
1003 s.run_time = 0;
1004 s.avg_sim_fps = 0;
1005 s.min_sim_fps = 0;
1006 s.max_sim_fps = 0;
1007 s.mode_sim_fps = 0;
1008 s.start_time = 0;
1009 s.client_version = "";
1010 s.s_cpu = "";
1011 s.s_gpu = "";
1012 s.s_os = "";
1013 s.s_ram = 0;
1014 s.d_object_kb = 0;
1015 s.d_texture_kb = 0;
1016 s.d_world_kb = 0;
1017 s.n_in_kb = 0;
1018 s.n_in_pk = 0;
1019 s.n_out_kb = 0;
1020 s.n_out_pk = 0;
1021 s.f_dropped = 0;
1022 s.f_failed_resends = 0;
1023 s.f_invalid = 0;
1024 s.f_off_circuit = 0;
1025 s.f_resent = 0;
1026 s.f_send_packet = 0;
1027 s._ping = new List<float>();
1028 s._fps = new List<float>();
1029 s._sim_fps = new List<float>();
1030 s._agents_in_view = new List<int>();
1031 return s;
1032 }
1033 }
1034 #region structs
1035
1036 public class UserSession
1037 {
1038 public UUID session_id;
1039 public UUID region_id;
1040 public string name_f;
1041 public string name_l;
1042 public UserSessionData session_data;
1043 }
1044
1045 public struct UserSessionData
1046 {
1047 public UUID session_id;
1048 public UUID agent_id;
1049 public UUID region_id;
1050 public float last_updated;
1051 public string remote_ip;
1052 public string name_f;
1053 public string name_l;
1054 public float avg_agents_in_view;
1055 public float min_agents_in_view;
1056 public float max_agents_in_view;
1057 public float mode_agents_in_view;
1058 public float avg_fps;
1059 public float min_fps;
1060 public float max_fps;
1061 public float mode_fps;
1062 public string a_language;
1063 public float mem_use;
1064 public float meters_traveled;
1065 public float avg_ping;
1066 public float min_ping;
1067 public float max_ping;
1068 public float mode_ping;
1069 public int regions_visited;
1070 public float run_time;
1071 public float avg_sim_fps;
1072 public float min_sim_fps;
1073 public float max_sim_fps;
1074 public float mode_sim_fps;
1075 public float start_time;
1076 public string client_version;
1077 public string s_cpu;
1078 public string s_gpu;
1079 public string s_os;
1080 public int s_ram;
1081 public float d_object_kb;
1082 public float d_texture_kb;
1083 public float d_world_kb;
1084 public float n_in_kb;
1085 public int n_in_pk;
1086 public float n_out_kb;
1087 public int n_out_pk;
1088 public int f_dropped;
1089 public int f_failed_resends;
1090 public int f_invalid;
1091 public int f_off_circuit;
1092 public int f_resent;
1093 public int f_send_packet;
1094 public List<float> _ping;
1095 public List<float> _fps;
1096 public List<float> _sim_fps;
1097 public List<int> _agents_in_view;
1098 }
1099
1100 #endregion
1101
1102 public class USimStatsData
1103 {
1104 private UUID m_regionID = UUID.Zero;
1105 private volatile int m_statcounter = 0;
1106 private volatile float m_timeDilation;
1107 private volatile float m_simFps;
1108 private volatile float m_physicsFps;
1109 private volatile float m_agentUpdates;
1110 private volatile float m_rootAgents;
1111 private volatile float m_childAgents;
1112 private volatile float m_totalPrims;
1113 private volatile float m_activePrims;
1114 private volatile float m_totalFrameTime;
1115 private volatile float m_netFrameTime;
1116 private volatile float m_physicsFrameTime;
1117 private volatile float m_otherFrameTime;
1118 private volatile float m_imageFrameTime;
1119 private volatile float m_inPacketsPerSecond;
1120 private volatile float m_outPacketsPerSecond;
1121 private volatile float m_unackedBytes;
1122 private volatile float m_agentFrameTime;
1123 private volatile float m_pendingDownloads;
1124 private volatile float m_pendingUploads;
1125 private volatile float m_activeScripts;
1126 private volatile float m_scriptLinesPerSecond;
1127
1128 public UUID RegionId { get { return m_regionID; } }
1129 public int StatsCounter { get { return m_statcounter; } set { m_statcounter = value;}}
1130 public float TimeDilation { get { return m_timeDilation; } }
1131 public float SimFps { get { return m_simFps; } }
1132 public float PhysicsFps { get { return m_physicsFps; } }
1133 public float AgentUpdates { get { return m_agentUpdates; } }
1134 public float RootAgents { get { return m_rootAgents; } }
1135 public float ChildAgents { get { return m_childAgents; } }
1136 public float TotalPrims { get { return m_totalPrims; } }
1137 public float ActivePrims { get { return m_activePrims; } }
1138 public float TotalFrameTime { get { return m_totalFrameTime; } }
1139 public float NetFrameTime { get { return m_netFrameTime; } }
1140 public float PhysicsFrameTime { get { return m_physicsFrameTime; } }
1141 public float OtherFrameTime { get { return m_otherFrameTime; } }
1142 public float ImageFrameTime { get { return m_imageFrameTime; } }
1143 public float InPacketsPerSecond { get { return m_inPacketsPerSecond; } }
1144 public float OutPacketsPerSecond { get { return m_outPacketsPerSecond; } }
1145 public float UnackedBytes { get { return m_unackedBytes; } }
1146 public float AgentFrameTime { get { return m_agentFrameTime; } }
1147 public float PendingDownloads { get { return m_pendingDownloads; } }
1148 public float PendingUploads { get { return m_pendingUploads; } }
1149 public float ActiveScripts { get { return m_activeScripts; } }
1150 public float ScriptLinesPerSecond { get { return m_scriptLinesPerSecond; } }
1151
1152 public USimStatsData(UUID pRegionID)
1153 {
1154 m_regionID = pRegionID;
1155 }
1156
1157 public void ConsumeSimStats(SimStats stats)
1158 {
1159 m_regionID = stats.RegionUUID;
1160 m_timeDilation = stats.StatsBlock[0].StatValue;
1161 m_simFps = stats.StatsBlock[1].StatValue;
1162 m_physicsFps = stats.StatsBlock[2].StatValue;
1163 m_agentUpdates = stats.StatsBlock[3].StatValue;
1164 m_rootAgents = stats.StatsBlock[4].StatValue;
1165 m_childAgents = stats.StatsBlock[5].StatValue;
1166 m_totalPrims = stats.StatsBlock[6].StatValue;
1167 m_activePrims = stats.StatsBlock[7].StatValue;
1168 m_totalFrameTime = stats.StatsBlock[8].StatValue;
1169 m_netFrameTime = stats.StatsBlock[9].StatValue;
1170 m_physicsFrameTime = stats.StatsBlock[10].StatValue;
1171 m_otherFrameTime = stats.StatsBlock[11].StatValue;
1172 m_imageFrameTime = stats.StatsBlock[12].StatValue;
1173 m_inPacketsPerSecond = stats.StatsBlock[13].StatValue;
1174 m_outPacketsPerSecond = stats.StatsBlock[14].StatValue;
1175 m_unackedBytes = stats.StatsBlock[15].StatValue;
1176 m_agentFrameTime = stats.StatsBlock[16].StatValue;
1177 m_pendingDownloads = stats.StatsBlock[17].StatValue;
1178 m_pendingUploads = stats.StatsBlock[18].StatValue;
1179 m_activeScripts = stats.StatsBlock[19].StatValue;
1180 m_scriptLinesPerSecond = stats.StatsBlock[20].StatValue;
1181 }
1182 }
1183} \ No newline at end of file