29 using System.Collections.Generic;
31 using System.Reflection;
37 using OpenSim.Framework;
38 using OpenSim.Framework.Console;
39 using OpenSim.Framework.Monitoring;
40 using OpenSim.Region.ClientStack.LindenUDP;
41 using OpenSim.Region.Framework.Interfaces;
42 using OpenSim.Region.Framework.Scenes;
52 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"LindenUDPInfoModule")]
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
57 protected Dictionary<UUID, Scene> m_scenes =
new Dictionary<UUID, Scene>();
59 public string Name {
get {
return "Linden UDP Module"; } }
61 public Type ReplaceableInterface {
get {
return null; } }
83 m_scenes[scene.RegionInfo.RegionID] = scene;
86 "Comms",
this,
"show pqueues",
87 "show pqueues [full]",
88 "Show priority queue data for each client",
89 "Without the 'full' option, only root agents are shown."
90 +
" With the 'full' option child agents are also shown.",
94 "Comms",
this,
"show queues",
96 "Show queue data for each client",
97 "Without the 'full' option, only root agents are shown.\n"
98 +
"With the 'full' option child agents are also shown.\n\n"
99 +
"Type - Rt is a root (avatar) client whilst cd is a child (neighbour interacting) client.\n"
100 +
"Since Last In - Time in milliseconds since last packet received.\n"
101 +
"Pkts In - Number of packets processed from the client.\n"
102 +
"Pkts Out - Number of packets sent to the client.\n"
103 +
"Pkts Resent - Number of packets resent to the client.\n"
104 +
"Bytes Unacked - Number of bytes transferred to the client that are awaiting acknowledgement.\n"
105 +
"Q Pkts * - Number of packets of various types (land, wind, etc.) to be sent to the client that are waiting for available bandwidth.\n",
109 "Comms",
this,
"show image queues",
110 "show image queues <first-name> <last-name>",
111 "Show the image queues (textures downloaded via UDP) for a particular client.",
115 "Comms",
this,
"clear image queues",
116 "clear image queues <first-name> <last-name>",
117 "Clear the image queues (textures downloaded via UDP) for a particular client.",
121 "Comms",
this,
"show throttles",
122 "show throttles [full]",
123 "Show throttle settings for each client and for the server overall",
124 "Without the 'full' option, only root agents are shown."
125 +
" With the 'full' option child agents are also shown.",
129 "Comms",
this,
"emergency-monitoring",
130 "emergency-monitoring",
131 "Go on/off emergency monitoring mode",
132 "Go on/off emergency monitoring mode",
133 HandleEmergencyMonitoring);
136 "Comms",
this,
"show client stats",
137 "show client stats [first_name last_name]",
138 "Show client request stats",
139 "Without the 'first_name last_name' option, all clients are shown."
140 +
" With the 'first_name last_name' option only a specific client is shown.",
150 m_scenes.Remove(scene.RegionInfo.RegionID);
161 return "Usage: image queues clear <first-name> <last-name>";
163 string firstName = cmd[3];
164 string lastName = cmd[4];
166 List<ScenePresence> foundAgents =
new List<ScenePresence>();
170 foreach (
Scene scene
in m_scenes.Values)
172 ScenePresence sp = scene.GetScenePresence(firstName, lastName);
178 if (foundAgents.Count == 0)
179 return string.Format(
"No agents found for {0} {1}", firstName, lastName);
181 StringBuilder report =
new StringBuilder();
188 return "This command is only supported for LLClientView";
190 int requestsDeleted = client.ImageManager.ClearImageQueue();
193 "In region {0} ({1} agent) cleared {2} requests\n",
194 agent.Scene.RegionInfo.RegionName, agent.IsChildAgent ?
"child" :
"root", requestsDeleted);
197 return report.ToString();
203 if (cmd.Length == 1 || (cmd.Length > 1 && cmd[1] ==
"on"))
206 MainConsole.Instance.Output(
"Emergency Monitoring ON");
211 MainConsole.Instance.Output(
"Emergency Monitoring OFF");
214 foreach (
Scene s
in m_scenes.Values)
215 s.EmergencyMonitoring = mode;
220 return string.Format(
221 "{0,-" + maxLength +
"}{1,-" + columnPadding +
"}",
222 entry.Length > maxLength ? entry.Substring(0, maxLength) : entry,
233 bool showChildren =
false;
236 if (showParams.Length > 2 && showParams[2] ==
"full")
238 else if (showParams.Length > 3)
239 pname = showParams[2] +
" " + showParams[3];
241 StringBuilder report =
new StringBuilder();
243 int columnPadding = 2;
244 int maxNameLength = 18;
245 int maxRegionNameLength = 14;
246 int maxTypeLength = 4;
249 report.Append(GetColumnEntry(
"User", maxNameLength, columnPadding));
250 report.Append(GetColumnEntry(
"Region", maxRegionNameLength, columnPadding));
251 report.Append(GetColumnEntry(
"Type", maxTypeLength, columnPadding));
254 "{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7} {10,7} {11,7}\n",
270 foreach (
Scene scene
in m_scenes.Values)
277 bool isChild = client.SceneAgent.IsChildAgent;
278 if (isChild && !showChildren)
281 string name = client.Name;
282 if (pname !=
"" && name != pname)
285 string regionName = scene.RegionInfo.RegionName;
287 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
288 report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
289 report.Append(GetColumnEntry(isChild ?
"Cd" :
"Rt", maxTypeLength, columnPadding));
290 report.AppendLine(((LLClientView)client).EntityUpdateQueue.ToString());
296 return report.ToString();
304 private string GetImageQueuesReport(
string[] showParams)
306 if (showParams.Length < 5 || showParams.Length > 6)
307 return "Usage: show image queues <first-name> <last-name> [full]";
309 string firstName = showParams[3];
310 string lastName = showParams[4];
312 bool showChildAgents = showParams.Length == 6;
314 List<ScenePresence> foundAgents =
new List<ScenePresence>();
318 foreach (
Scene scene
in m_scenes.Values)
320 ScenePresence sp = scene.GetScenePresence(firstName, lastName);
321 if (sp != null && (showChildAgents || !sp.
IsChildAgent))
326 if (foundAgents.Count == 0)
327 return string.Format(
"No agents found for {0} {1}", firstName, lastName);
329 StringBuilder report =
new StringBuilder();
336 return "This command is only supported for LLClientView";
338 J2KImage[] images = client.ImageManager.GetImages();
341 "In region {0} ({1} agent)\n",
342 agent.Scene.RegionInfo.RegionName, agent.IsChildAgent ?
"child" :
"root");
343 report.AppendFormat(
"Images in queue: {0}\n", images.Length);
345 if (images.Length > 0)
348 "{0,-36} {1,-8} {2,-10} {3,-9} {4,-9} {5,-7}\n",
358 "{0,36} {1,8} {2,10} {3,10} {4,9} {5,7}\n",
359 image.TextureID, image.LastSequence, image.Priority, image.StartPacket, image.HasAsset, image.IsDecoded);
363 return report.ToString();
373 bool showChildren =
false;
376 if (showParams.Length > 2 && showParams[2] ==
"full")
378 else if (showParams.Length > 3)
379 pname = showParams[2] +
" " + showParams[3];
381 StringBuilder report =
new StringBuilder();
383 int columnPadding = 2;
384 int maxNameLength = 18;
385 int maxRegionNameLength = 14;
386 int maxTypeLength = 4;
388 int totalInfoFieldsLength
389 = maxNameLength + columnPadding
390 + maxRegionNameLength + columnPadding
391 + maxTypeLength + columnPadding;
393 report.Append(GetColumnEntry(
"User", maxNameLength, columnPadding));
394 report.Append(GetColumnEntry(
"Region", maxRegionNameLength, columnPadding));
395 report.Append(GetColumnEntry(
"Type", maxTypeLength, columnPadding));
398 "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7}\n",
412 report.AppendFormat(
"{0,-" + totalInfoFieldsLength +
"}",
"");
414 "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7}\n",
430 foreach (
Scene scene
in m_scenes.Values)
438 bool isChild = client.SceneAgent.IsChildAgent;
439 if (isChild && !showChildren)
442 string name = client.Name;
443 if (pname !=
"" && name != pname)
446 string regionName = scene.RegionInfo.RegionName;
448 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
449 report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
450 report.Append(GetColumnEntry(isChild ?
"Cd" :
"Rt", maxTypeLength, columnPadding));
452 IStatsCollector stats = (IStatsCollector)client;
453 report.AppendLine(stats.Report());
459 return report.ToString();
469 bool showChildren =
false;
472 if (showParams.Length > 2 && showParams[2] ==
"full")
474 else if (showParams.Length > 3)
475 pname = showParams[2] +
" " + showParams[3];
477 StringBuilder report =
new StringBuilder();
479 int columnPadding = 2;
480 int maxNameLength = 18;
481 int maxRegionNameLength = 14;
482 int maxTypeLength = 4;
483 int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding;
485 report.Append(GetColumnEntry(
"User", maxNameLength, columnPadding));
486 report.Append(GetColumnEntry(
"Region", maxRegionNameLength, columnPadding));
487 report.Append(GetColumnEntry(
"Type", maxTypeLength, columnPadding));
490 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
502 report.AppendFormat(
"{0,-" + totalInfoFieldsLength +
"}",
"");
504 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
520 foreach (
Scene scene
in m_scenes.Values)
525 if (client is LLClientView)
527 LLClientView llClient = client as LLClientView;
529 bool isChild = client.SceneAgent.IsChildAgent;
530 if (isChild && !showChildren)
533 string name = client.Name;
534 if (pname !=
"" && name != pname)
537 string regionName = scene.RegionInfo.RegionName;
542 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
543 report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
544 report.Append(GetColumnEntry(isChild ?
"Cd" :
"Rt", maxTypeLength, columnPadding));
547 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
548 ci.maxThrottle > 0 ? ((ci.maxThrottle * 8) / 1000).ToString() :
"-",
551 : (llUdpClient.FlowThrottle.TotalDripRequest * 8 / 1000).ToString(),
552 (ci.totalThrottle * 8) / 1000,
554 (ci.landThrottle * 8) / 1000,
556 (ci.cloudThrottle * 8) / 1000,
558 (ci.textureThrottle * 8) / 1000,
565 return report.ToString();
578 if (showParams.Length <= 4)
580 m_log.InfoFormat(
"[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}",
"Region",
"Name",
"Root",
"Time",
"Reqs/min",
"AgentUpdates");
581 foreach (
Scene scene
in m_scenes.Values)
586 if (client is LLClientView)
588 LLClientView llClient = client as LLClientView;
589 ClientInfo cinfo = llClient.UDPClient.GetClientInfo();
590 int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.
GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
591 avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
593 string childAgentStatus;
596 childAgentStatus = llClient.SceneAgent.IsChildAgent ?
"N" :
"Y";
598 childAgentStatus =
"Off!";
600 m_log.InfoFormat(
"[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}",
601 scene.RegionInfo.RegionName, llClient.Name,
603 (DateTime.Now - cinfo.StartedTime).Minutes,
617 string fname =
"", lname =
"";
619 if (showParams.Length > 3)
620 fname = showParams[3];
621 if (showParams.Length > 4)
622 lname = showParams[4];
624 foreach (
Scene scene
in m_scenes.Values)
629 if (client is LLClientView)
631 LLClientView llClient = client as LLClientView;
633 if (llClient.
Name == fname +
" " + lname)
637 AgentCircuitData aCircuit = scene.AuthenticateHandler.GetAgentCircuitData(llClient.CircuitCode);
638 if (aCircuit == null)
642 m_log.InfoFormat(
"[INFO]: {0} # {1} # {2}", llClient.Name, Util.GetViewerName(aCircuit), aCircuit.Id0);
644 int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.
GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
645 avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
647 m_log.InfoFormat(
"[INFO]:");
648 m_log.InfoFormat(
"[INFO]: {0} # {1} # Time: {2}min # Avg Reqs/min: {3}", scene.RegionInfo.RegionName,
649 (llClient.SceneAgent.IsChildAgent ?
"Child" :
"Root"), (DateTime.Now - cinfo.
StartedTime).Minutes, avg_reqs);
651 Dictionary<string, int> sortedDict = (from entry in cinfo.AsyncRequests orderby entry.Value descending select entry)
652 .ToDictionary(pair => pair.Key, pair => pair.Value);
653 PrintRequests(
"TOP ASYNC", sortedDict, cinfo.
AsyncRequests.Values.Sum());
655 sortedDict = (from entry in cinfo.SyncRequests orderby entry.Value descending select entry)
656 .ToDictionary(pair => pair.Key, pair => pair.Value);
657 PrintRequests(
"TOP SYNC", sortedDict, cinfo.
SyncRequests.Values.Sum());
659 sortedDict = (from entry in cinfo.GenericRequests orderby entry.Value descending select entry)
660 .ToDictionary(pair => pair.Key, pair => pair.Value);
661 PrintRequests(
"TOP GENERIC", sortedDict, cinfo.
GenericRequests.Values.Sum());
669 private void PrintRequests(
string type, Dictionary<string, int> sortedDict,
int sum)
671 m_log.InfoFormat(
"[INFO]:");
672 m_log.InfoFormat(
"[INFO]: {0,25}", type);
673 foreach (KeyValuePair<string, int> kvp
in sortedDict.Take(12))
674 m_log.InfoFormat(
"[INFO]: {0,25} {1,-6}", kvp.Key, kvp.Value);
675 m_log.InfoFormat(
"[INFO]: {0,25}",
"...");
676 m_log.InfoFormat(
"[INFO]: {0,25} {1,-6}",
"Total", sum);
Implemented by classes which collect up non-viewer statistical information
string HandleClientStatsReport(string[] showParams)
Show client stats data
Handles new client connections Constructor takes a single Packet and authenticates everything ...
bool IsChildAgent
If true, then the agent has no avatar in the scene. The agent exists to relay data from a region that...
Dictionary< string, int > GenericRequests
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void HandleEmergencyMonitoring(string module, string[] cmd)
string Name
Full name of the client (first name and last name)
string GetPQueuesReport(string[] showParams)
Generate UDP Queue data report for each client
Tracks state for a client UDP connection and provides client-specific methods
Dictionary< string, int > SyncRequests
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
Stores information about a current texture download and a reference to the texture asset ...
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Circuit data for an agent. Connection information shared between regions that accept UDP connections ...
string GetThrottlesReport(string[] showParams)
Show throttle data
static ICommandConsole Instance
void Output(string text, string level)
string HandleImageQueuesClear(string[] cmd)
Interactive OpenSim region server
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
AdaptiveTokenBucket FlowThrottle
string GetQueuesReport(string[] showParams)
Generate UDP Queue data report for each client
readonly DateTime StartedTime
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
A module that just holds commands for inspecting the current state of the Linden UDP stack...
Dictionary< string, int > AsyncRequests
string GetColumnEntry(string entry, int maxLength, int columnPadding)