Performance improvements:
[mono.git] / mcs / class / System.Web / System.Web / TraceData.cs
1 //
2 // System.Web.TraceData
3 //
4 // Author(s):
5 //  Jackson Harper (jackson@ximian.com)
6 //
7 // (C) 2004 Novell, Inc (http://www.novell.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31
32 using System;
33 using System.Collections;
34 using System.Globalization;
35 using System.IO;
36 using System.Text;
37 using System.Web.UI;
38 using System.Web.UI.WebControls;
39
40 #if NET_2_0
41 using System.Collections.Generic;
42 #endif
43
44 namespace System.Web {
45
46         class InfoTraceData
47         {
48                 public string Category;
49                 public string Message;
50                 public string Exception;
51                 public double TimeSinceFirst;
52                 public double TimeSinceLast;
53                 public bool IsWarning;
54
55                 public InfoTraceData (string category, string message, string exception, double timeSinceFirst, double timeSinceLast, bool isWarning)
56                 {
57                         this.Category = category;
58                         this.Message = message;
59                         this.Exception = exception;
60                         this.TimeSinceFirst = timeSinceFirst;
61                         this.TimeSinceLast = timeSinceLast;
62                         this.IsWarning = isWarning;
63                 }
64         }
65
66         class ControlTraceData
67         {
68                 public string ControlId;
69                 public Type Type;
70                 public int RenderSize;
71                 public int ViewstateSize;
72                 public int Depth;
73 #if NET_2_0
74                 public int ControlstateSize;
75 #endif
76
77 #if NET_2_0
78                 public ControlTraceData (string controlId, Type type, int renderSize, int viewstateSize, int controlstateSize, int depth)
79 #else
80                 public ControlTraceData (string controlId, Type type, int renderSize, int viewstateSize, int depth)
81 #endif
82                 {
83                         this.ControlId = controlId;
84                         this.Type = type;
85                         this.RenderSize = renderSize;
86                         this.ViewstateSize = viewstateSize;
87                         this.Depth = depth;
88 #if NET_2_0
89                         this.ControlstateSize = controlstateSize;
90 #endif
91                 }
92         }
93
94         class NameValueTraceData
95         {
96                 public string Name;
97                 public string Value;
98
99                 public NameValueTraceData (string name, string value)
100                 {
101                         this.Name = name;
102                         this.Value = value;
103                 }
104         }
105         
106         internal class TraceData {
107
108                 bool is_first_time;
109                 DateTime first_time;
110                 double prev_time;
111
112 #if NET_2_0
113                 Queue <InfoTraceData> info;
114                 Queue <ControlTraceData> control_data;
115                 Queue <NameValueTraceData> cookie_data;
116                 Queue <NameValueTraceData> header_data;
117                 Queue <NameValueTraceData> servervar_data;
118                 Hashtable ctrl_cs;
119 #else
120                 Queue info;
121                 Queue control_data;
122                 Queue cookie_data;
123                 Queue header_data;
124                 Queue servervar_data;
125                 //DataTable viewstate_data;
126 #endif
127                 
128                 string request_path;
129                 string session_id;
130                 DateTime request_time;
131                 Encoding request_encoding;
132                 Encoding response_encoding;
133                 string request_type;
134                 int status_code;
135                 Page page;
136                 TraceMode _traceMode = HttpRuntime.TraceManager.TraceMode;
137
138                 public TraceData ()
139                 {
140 #if NET_2_0
141                         info = new Queue <InfoTraceData> ();
142                         control_data = new Queue <ControlTraceData> ();
143                         cookie_data = new Queue <NameValueTraceData> ();
144                         header_data = new Queue <NameValueTraceData> ();
145                         servervar_data = new Queue <NameValueTraceData> ();
146 #else
147                         info = new Queue ();
148                         control_data = new Queue ();
149                         cookie_data = new Queue ();
150                         header_data = new Queue ();
151                         servervar_data = new Queue ();
152 #endif
153
154                         /* TODO
155                         viewstate_data = new DataTable ();
156                         viewstate_data.Columns.Add (new DataColumn ("ControlId", typeof (string)));
157                         viewstate_data.Columns.Add (new DataColumn ("Data", typeof (string)));
158                         */
159
160                         is_first_time = true;
161                 }
162
163                 public TraceMode TraceMode {
164                         get { return _traceMode; }
165                         set { _traceMode = value; }
166                 }
167
168                 public string RequestPath {
169                         get { return request_path; }
170                         set { request_path = value; }
171                 }
172                 
173                 public string SessionID {
174                         get { return session_id; }
175                         set { session_id = value; }
176                 }
177
178                 public DateTime RequestTime {
179                         get { return request_time; }
180                         set { request_time = value; }
181                 }
182
183                 public Encoding RequestEncoding {
184                         get { return request_encoding; }
185                         set { request_encoding = value; }
186                 }
187
188                 public Encoding ResponseEncoding {
189                         get { return response_encoding; }
190                         set { response_encoding = value; }
191                 }
192
193                 public string RequestType {
194                         get { return request_type; }
195                         set { request_type = value; }
196                 }
197
198                 public int StatusCode {
199                         get { return status_code; }
200                         set { status_code = value; }
201                 }
202
203                 public void Write (string category, string msg, Exception error, bool Warning)
204                 {
205                         double time;
206                         double time_from_last;
207                         if (is_first_time) {
208                                 time = 0;
209                                 time_from_last = 0; 
210                                 prev_time = 0;
211                                 is_first_time = false;
212                                 first_time = DateTime.Now;
213                         }
214                         else {
215                                 time = (DateTime.Now - first_time).TotalSeconds;
216                                 time_from_last = time - prev_time;
217                                 prev_time = time;
218                         }
219
220                         info.Enqueue (
221                                 new InfoTraceData (category,
222                                                    HtmlEncode (msg),
223                                                    (error != null ? error.ToString () : null),
224                                                    time,
225                                                    time_from_last,
226                                                    Warning));
227                 }
228
229                 static string HtmlEncode (string s)
230                 {
231                         if (s == null)
232                                 return "";
233
234                         string res = HttpUtility.HtmlEncode (s);
235                         res = res.Replace ("\n", "<br>");
236                         return res.Replace (" ", "&nbsp;");
237                 }
238                 
239 #if NET_2_0
240                 public void AddControlTree (Page page, Hashtable ctrl_vs, Hashtable ctrl_cs, Hashtable sizes)
241 #else
242                 public void AddControlTree (Page page, Hashtable ctrl_vs, Hashtable sizes)
243 #endif
244                 {
245                         this.page = page;
246                         this.ctrl_vs = ctrl_vs;
247                         this.sizes = sizes;
248 #if NET_2_0
249                         this.ctrl_cs = ctrl_cs;
250 #endif
251                         AddControl (page, 0);
252                 }
253
254                 Hashtable sizes;
255                 Hashtable ctrl_vs;
256                 void AddControl (Control c, int control_pos)
257                 {
258                         control_data.Enqueue (
259                                 new ControlTraceData (
260                                         c.UniqueID,
261                                         c.GetType (),
262                                         GetRenderSize (c),
263                                         GetViewStateSize (c, (ctrl_vs != null) ? ctrl_vs [c] : null),
264 #if NET_2_0
265                                         GetViewStateSize (c, (ctrl_cs != null) ? ctrl_cs [c] : null),
266 #endif
267                                         control_pos));
268                         
269                         if (c.HasControls ()) {
270                                 foreach (Control child in c.Controls)
271                                         AddControl (child, control_pos + 1);
272                         }
273                 }
274
275                 int GetRenderSize (Control ctrl)
276                 {
277                         if (sizes == null)
278                                 return 0;
279
280                         object s = sizes [ctrl];
281                         return s == null ? 0 : (int) s;
282                 }
283
284                 static int GetViewStateSize (Control ctrl, object vs)
285                 {
286                         if (vs == null)
287                                 return 0;
288
289                         StringWriter sr = new StringWriter ();
290                         LosFormatter fmt = new LosFormatter ();
291                         fmt.Serialize (sr, vs);
292                         return sr.GetStringBuilder ().Length;
293                 }
294
295                 public void AddCookie (string name, string value)
296                 {
297                         cookie_data.Enqueue (new NameValueTraceData (name, value));
298                 }
299
300                 public void AddHeader (string name, string value)
301                 {
302                         header_data.Enqueue (new NameValueTraceData (name, value));
303                 }
304
305                 public void AddServerVar (string name, string value)
306                 {
307                         servervar_data.Enqueue (new NameValueTraceData (name, value));
308                 }
309                 
310                 public void Render (HtmlTextWriter output)
311                 {
312                         output.AddAttribute ("id", "__asptrace");
313                         output.RenderBeginTag (HtmlTextWriterTag.Div);
314                         
315                         RenderStyleSheet (output);
316                         
317                         output.AddAttribute ("class", "tracecontent");
318                         output.RenderBeginTag (HtmlTextWriterTag.Span);
319                         
320                         RenderRequestDetails (output);
321                         RenderTraceInfo (output);
322                         RenderControlTree (output);
323                         RenderCookies (output);
324                         RenderHeaders (output);
325                         RenderServerVars (output);
326                         
327                         output.RenderEndTag ();
328                         output.RenderEndTag ();
329                 }
330                 
331                 void RenderRequestDetails (HtmlTextWriter output)
332                 {
333                         Table table = CreateTable ();
334                         
335                         table.Rows.Add (AltRow ("Request Details:"));
336                         table.Rows.Add (InfoRow2 ("Session Id:", session_id,
337                                                         "Request Type", request_type));
338                         table.Rows.Add (InfoRow2 ("Time of Request:", request_time.ToString (),
339                                                         "State Code:", status_code.ToString ()));
340                         table.Rows.Add (InfoRow2 ("Request Encoding:", request_encoding.EncodingName,
341                                                    "Response Encoding:", response_encoding.EncodingName));           
342                         table.RenderControl (output);
343                 }
344                 
345                 void RenderTraceInfo (HtmlTextWriter output)
346                 {
347                         Table table = CreateTable ();
348                         
349                         table.Rows.Add (AltRow ("Trace Information"));
350                         table.Rows.Add (SubHeadRow ("Category", "Message", "From First(s)", "From Lasts(s)"));
351                         
352                         int pos = 0;
353 #if NET_2_0
354                         IEnumerable<InfoTraceData> enumerable = info;
355
356                         if (TraceMode == TraceMode.SortByCategory) {
357                                 List<InfoTraceData> list = new List<InfoTraceData> (info);
358                                 list.Sort (delegate (InfoTraceData x, InfoTraceData y) { return String.Compare (x.Category, y.Category, StringComparison.Ordinal); });
359                                 enumerable = list;
360                         }
361
362                         foreach (InfoTraceData i in enumerable)
363                                 RenderTraceInfoRow (table, i, pos++);
364 #else
365                         foreach (object o in info)
366                                 RenderTraceInfoRow (table, o as InfoTraceData, pos++);
367 #endif
368                         table.RenderControl (output);
369                 }
370                 
371                 void RenderControlTree (HtmlTextWriter output)
372                 {
373                         Table table = CreateTable ();
374                         
375                         int page_vs_size = page == null ? 0 : GetViewStateSize (page, page.GetSavedViewState ());
376                         table.Rows.Add (AltRow ("Control Tree"));
377                         table.Rows.Add (SubHeadRow ("Control Id", "Type",
378                                                 "Render Size Bytes (including children)",
379 #if TARGET_J2EE
380                                                 "ViewState Size (excluding children)"
381 #else
382                                                 String.Format ("ViewState Size (total: {0} bytes)(excluding children)",
383                                                                 page_vs_size)
384 #endif
385 #if NET_2_0
386                                                 ,"ControlState Size (excluding children)"
387 #endif
388                                                         ));
389                         
390                         int pos = 0;
391 #if NET_2_0
392                         foreach (ControlTraceData r in control_data)
393                                 RenderControlTraceDataRow (table, r, pos++);
394 #else
395                         foreach (object o in control_data)
396                                 RenderControlTraceDataRow (table, o as ControlTraceData, pos++);
397 #endif
398                         table.RenderControl (output);
399                 }
400
401                 void RenderControlTraceDataRow (Table table, ControlTraceData r, int pos)
402                 {
403                         if (r == null)
404                                 return;
405                         
406                         int depth = r.Depth;
407                         string prefix = String.Empty;
408                         for (int i=0; i<depth; i++)
409                                 prefix += "&nbsp;&nbsp;&nbsp;&nbsp;";
410                         RenderAltRow (table, pos, prefix + r.ControlId,
411                                       r.Type.ToString (), r.RenderSize.ToString (),
412 #if NET_2_0
413                                           r.ViewstateSize.ToString (), r.ControlstateSize.ToString ());
414 #else
415                                       r.ViewstateSize.ToString ());
416 #endif
417                 }
418                 
419                 void RenderCookies (HtmlTextWriter output)
420                 {
421                         Table table = CreateTable ();
422                         
423                         table.Rows.Add (AltRow ("Cookies Collection"));
424                         table.Rows.Add (SubHeadRow ("Name", "Value", "Size"));
425                         
426                         int pos = 0;
427 #if NET_2_0
428                         foreach (NameValueTraceData r in cookie_data)
429                                 RenderCookieDataRow (table, r, pos++);
430 #else
431                         foreach (object o in cookie_data)
432                                 RenderCookieDataRow (table, o as NameValueTraceData, pos++);
433 #endif          
434                         
435                         table.RenderControl (output);
436                 }
437
438                 void RenderCookieDataRow (Table table, NameValueTraceData r, int pos)
439                 {
440                         if (r == null)
441                                 return;
442                         
443                         int length = r.Name.Length + (r.Value == null ? 0 : r.Value.Length);
444                         RenderAltRow (table, pos++, r.Name, r.Value, length.ToString ());
445                 }
446                 
447                 void RenderHeaders (HtmlTextWriter output)
448                 {
449                         Table table = CreateTable ();
450                         
451                         table.Rows.Add (AltRow ("Headers Collection"));
452                         table.Rows.Add (SubHeadRow ("Name", "Value"));
453                         
454                         int pos = 0;
455 #if NET_2_0
456                         foreach (NameValueTraceData r in header_data)
457                                 RenderAltRow (table, pos++, r.Name, r.Value);
458 #else
459                         NameValueTraceData r;
460                         foreach (object o in header_data) {
461                                 r = o as NameValueTraceData;
462                                 if (r == null)
463                                         continue;
464                                 
465                                 RenderAltRow (table, pos++, r.Name, r.Value);
466                         }
467 #endif
468                         table.RenderControl (output);
469                 }
470                 
471                 void RenderServerVars (HtmlTextWriter output)
472                 {
473                         Table table = CreateTable ();
474                         
475                         table.Rows.Add (AltRow ("Server Variables"));
476                         table.Rows.Add (SubHeadRow ("Name", "Value"));
477                         
478                         int pos = 0;
479 #if NET_2_0
480                         foreach (NameValueTraceData r in servervar_data)
481                                 RenderAltRow (table, pos++, r.Name, r.Value);
482 #else
483                         NameValueTraceData r;
484                         foreach (object o in servervar_data) {
485                                 r = o as NameValueTraceData;
486                                 if (r == null)
487                                         continue;
488                                 
489                                 RenderAltRow (table, pos++, r.Name, r.Value);
490                         }
491 #endif                  
492                         table.RenderControl (output);
493                 }
494
495                 internal static TableRow AltRow (string title)
496                 {
497                         TableRow row = new TableRow ();
498                         TableHeaderCell header = new TableHeaderCell ();
499                         header.CssClass = "alt";
500                         header.HorizontalAlign = HorizontalAlign.Left;
501                         header.Attributes [" colspan"] = "10";
502                         header.Text = "<h3><b>" + title + "</b></h3>";
503
504                         row.Cells.Add (header);
505                         return row;
506                 }
507                 
508                 void RenderTraceInfoRow (Table table, InfoTraceData i, int pos)
509                 {
510                         if (i == null)
511                                 return;
512                         
513                         string open, close;
514                         open = close = String.Empty;
515                         if ((bool) i.IsWarning) {
516                                 open = "<span style=\"color:red\">";
517                                 close = "</span>";
518                         }
519
520                         string t1, t2;
521 #if !TARGET_J2EE
522                         if (i.TimeSinceFirst == 0) {
523                                 t1 = t2 = String.Empty;
524                         } else
525 #endif
526                         {
527                                 t1 = i.TimeSinceFirst.ToString ("0.000000");
528                                 if (i.TimeSinceLast >= 0.1)
529                                         t2 = "<span style=\"color:red;font-weight:bold\">" + i.TimeSinceLast.ToString ("0.000000") + "</span>";
530                                 else
531                                         t2 = i.TimeSinceLast.ToString ("0.000000");
532                         }
533                         
534                         RenderAltRow (table, pos, open + (string) i.Category + close,
535                                       open + (string) i.Message + close, t1, t2);
536                 }
537            
538                 internal static TableRow SubHeadRow (params string[] cells)
539                 {
540                         TableRow row = new TableRow ();
541                         foreach (string s in cells) {
542                                 TableHeaderCell cell = new TableHeaderCell ();
543                                 cell.Text = s;
544                                 row.Cells.Add (cell);
545                         }
546                         
547                         row.CssClass = "subhead";
548                         row.HorizontalAlign = HorizontalAlign.Left;
549                         
550                         return row;
551                 }
552                 
553                 internal static TableRow RenderAltRow (Table table, int pos, params string[] cells)
554                 {
555                         TableRow row = new TableRow ();
556                         foreach (string s in cells) {
557                                 TableCell cell = new TableCell ();
558                                 cell.Text = s;
559                                 row.Cells.Add (cell);
560                    }
561                         
562                         if ((pos % 2) != 0)
563                                 row.CssClass = "alt";
564                         
565                         table.Rows.Add (row);
566                         return row;
567                 }
568            
569                 TableRow InfoRow2 (string title1, string info1, string title2, string info2)
570                 {
571                         TableRow row = new TableRow ();
572                         TableHeaderCell header1 = new TableHeaderCell ();
573                         TableHeaderCell header2 = new TableHeaderCell ();
574                         TableCell cell1 = new TableCell ();
575                         TableCell cell2 = new TableCell ();
576                         
577                         header1.Text = title1;
578                         header2.Text = title2;
579                         cell1.Text = info1;
580                         cell2.Text = info2;
581                         
582                         row.Cells.Add (header1);
583                         row.Cells.Add (cell1);
584                         row.Cells.Add (header2);
585                         row.Cells.Add (cell2);
586
587                         row.HorizontalAlign = HorizontalAlign.Left;
588                         
589                         return row;
590                 }
591                 
592                 internal static Table CreateTable ()
593                 {
594                         Table table = new Table ();
595                         
596                         table.Width = Unit.Percentage (100);
597                         table.CellSpacing = 0;
598                         table.CellPadding = 0;
599                         
600                         return table;
601                 }
602                 
603                 internal static void RenderStyleSheet (HtmlTextWriter o)
604                 {
605                         o.WriteLine ("<style type=\"text/css\">");
606                         o.Write ("span.tracecontent { background-color:white; ");
607                         o.WriteLine ("color:black;font: 10pt verdana, arial; }");
608                         o.Write ("span.tracecontent table { font: 10pt verdana, ");
609                         o.WriteLine ("arial; cellspacing:0; cellpadding:0; margin-bottom:25}");
610                         o.WriteLine ("span.tracecontent tr.subhead { background-color:cccccc;}");
611                         o.WriteLine ("span.tracecontent th { padding:0,3,0,3 }");
612                         o.WriteLine ("span.tracecontent th.alt { background-color:black; color:white; padding:3,3,2,3; }");
613                         o.WriteLine ("span.tracecontent td { padding:0,3,0,3 }");
614                         o.WriteLine ("span.tracecontent tr.alt { background-color:eeeeee }");
615                         o.WriteLine ("span.tracecontent h1 { font: 24pt verdana, arial; margin:0,0,0,0}");
616                         o.WriteLine ("span.tracecontent h2 { font: 18pt verdana, arial; margin:0,0,0,0}");
617                         o.WriteLine ("span.tracecontent h3 { font: 12pt verdana, arial; margin:0,0,0,0}");
618                         o.WriteLine ("span.tracecontent th a { color:darkblue; font: 8pt verdana, arial; }");
619                         o.WriteLine ("span.tracecontent a { color:darkblue;text-decoration:none }");
620                         o.WriteLine ("span.tracecontent a:hover { color:darkblue;text-decoration:underline; }");
621                         o.WriteLine ("span.tracecontent div.outer { width:90%; margin:15,15,15,15}");
622                         o.Write ("span.tracecontent table.viewmenu td { background-color:006699; ");
623                         o.WriteLine ("color:white; padding:0,5,0,5; }");
624                         o.WriteLine ("span.tracecontent table.viewmenu td.end { padding:0,0,0,0; }");
625                         o.WriteLine ("span.tracecontent table.viewmenu a {color:white; font: 8pt verdana, arial; }");
626                         o.WriteLine ("span.tracecontent table.viewmenu a:hover {color:white; font: 8pt verdana, arial; }");
627                         o.WriteLine ("span.tracecontent a.tinylink {color:darkblue; font: 8pt verdana, ");
628                         o.WriteLine ("arial;text-decoration:underline;}");
629                         o.WriteLine ("span.tracecontent a.link {color:darkblue; text-decoration:underline;}");
630                         o.WriteLine ("span.tracecontent div.buffer {padding-top:7; padding-bottom:17;}");
631                         o.WriteLine ("span.tracecontent .small { font: 8pt verdana, arial }");
632                         o.WriteLine ("span.tracecontent table td { padding-right:20 }");
633                         o.WriteLine ("span.tracecontent table td.nopad { padding-right:5 }");
634                         o.WriteLine ("</style>");
635                 }
636         }
637 }
638