Merge pull request #1225 from strawd/bug22307
[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-2009 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.Collections.Generic;
35 using System.Globalization;
36 using System.IO;
37 using System.Text;
38 using System.Web.UI;
39 using System.Web.UI.WebControls;
40
41 namespace System.Web
42 {
43         sealed class InfoTraceData
44         {
45                 public string Category;
46                 public string Message;
47                 public string Exception;
48                 public double TimeSinceFirst;
49                 public double TimeSinceLast;
50                 public bool IsWarning;
51
52                 public InfoTraceData (string category, string message, string exception, double timeSinceFirst, double timeSinceLast, bool isWarning)
53                 {
54                         this.Category = category;
55                         this.Message = message;
56                         this.Exception = exception;
57                         this.TimeSinceFirst = timeSinceFirst;
58                         this.TimeSinceLast = timeSinceLast;
59                         this.IsWarning = isWarning;
60                 }
61         }
62
63         sealed class ControlTraceData
64         {
65                 public string ControlId;
66                 public Type Type;
67                 public int RenderSize;
68                 public int ViewstateSize;
69                 public int Depth;
70                 public int ControlstateSize;
71
72                 public ControlTraceData (string controlId, Type type, int renderSize, int viewstateSize, int controlstateSize, int depth)
73                 {
74                         this.ControlId = controlId;
75                         this.Type = type;
76                         this.RenderSize = renderSize;
77                         this.ViewstateSize = viewstateSize;
78                         this.Depth = depth;
79                         this.ControlstateSize = controlstateSize;
80                 }
81         }
82
83         sealed class NameValueTraceData
84         {
85                 public string Name;
86                 public string Value;
87
88                 public NameValueTraceData (string name, string value)
89                 {
90                         this.Name = name;
91                         this.Value = value;
92                 }
93         }
94         
95         sealed class TraceData
96         {
97                 bool is_first_time;
98                 DateTime first_time;
99                 double prev_time;
100                 Queue <InfoTraceData> info;
101                 Queue <ControlTraceData> control_data;
102                 Queue <NameValueTraceData> cookie_data;
103                 Queue <NameValueTraceData> header_data;
104                 Queue <NameValueTraceData> servervar_data;
105                 Hashtable ctrl_cs;
106                 string request_path;
107                 string session_id;
108                 DateTime request_time;
109                 Encoding request_encoding;
110                 Encoding response_encoding;
111                 string request_type;
112                 int status_code;
113                 Page page;
114                 TraceMode _traceMode = HttpRuntime.TraceManager.TraceMode;
115
116                 public TraceData ()
117                 {
118                         info = new Queue <InfoTraceData> ();
119                         control_data = new Queue <ControlTraceData> ();
120                         cookie_data = new Queue <NameValueTraceData> ();
121                         header_data = new Queue <NameValueTraceData> ();
122                         servervar_data = new Queue <NameValueTraceData> ();
123
124                         /* TODO
125                         viewstate_data = new DataTable ();
126                         viewstate_data.Columns.Add (new DataColumn ("ControlId", typeof (string)));
127                         viewstate_data.Columns.Add (new DataColumn ("Data", typeof (string)));
128                         */
129
130                         is_first_time = true;
131                 }
132
133                 public TraceMode TraceMode {
134                         get { return _traceMode; }
135                         set { _traceMode = value; }
136                 }
137
138                 public string RequestPath {
139                         get { return request_path; }
140                         set { request_path = value; }
141                 }
142                 
143                 public string SessionID {
144                         get { return session_id; }
145                         set { session_id = value; }
146                 }
147
148                 public DateTime RequestTime {
149                         get { return request_time; }
150                         set { request_time = value; }
151                 }
152
153                 public Encoding RequestEncoding {
154                         get { return request_encoding; }
155                         set { request_encoding = value; }
156                 }
157
158                 public Encoding ResponseEncoding {
159                         get { return response_encoding; }
160                         set { response_encoding = value; }
161                 }
162
163                 public string RequestType {
164                         get { return request_type; }
165                         set { request_type = value; }
166                 }
167
168                 public int StatusCode {
169                         get { return status_code; }
170                         set { status_code = value; }
171                 }
172
173                 public void Write (string category, string msg, Exception error, bool Warning)
174                 {
175                         double time;
176                         double time_from_last;
177                         if (is_first_time) {
178                                 time = 0;
179                                 time_from_last = 0; 
180                                 prev_time = 0;
181                                 is_first_time = false;
182                                 first_time = DateTime.Now;
183                         }
184                         else {
185                                 time = (DateTime.Now - first_time).TotalSeconds;
186                                 time_from_last = time - prev_time;
187                                 prev_time = time;
188                         }
189
190                         info.Enqueue (
191                                 new InfoTraceData (category,
192                                                    HtmlEncode (msg),
193                                                    (error != null ? error.ToString () : null),
194                                                    time,
195                                                    time_from_last,
196                                                    Warning));
197                 }
198
199                 static string HtmlEncode (string s)
200                 {
201                         if (s == null)
202                                 return "";
203
204                         string res = HttpUtility.HtmlEncode (s);
205                         res = res.Replace ("\n", "<br>");
206                         return res.Replace (" ", "&nbsp;");
207                 }
208                 
209                 public void AddControlTree (Page page, Hashtable ctrl_vs, Hashtable ctrl_cs, Hashtable sizes)
210                 {
211                         this.page = page;
212                         this.ctrl_vs = ctrl_vs;
213                         this.sizes = sizes;
214                         this.ctrl_cs = ctrl_cs;
215                         AddControl (page, 0);
216                 }
217
218                 Hashtable sizes;
219                 Hashtable ctrl_vs;
220                 void AddControl (Control c, int control_pos)
221                 {
222                         control_data.Enqueue (
223                                 new ControlTraceData (
224                                         c.UniqueID,
225                                         c.GetType (),
226                                         GetRenderSize (c),
227                                         GetViewStateSize (c, (ctrl_vs != null) ? ctrl_vs [c] : null),
228                                         GetViewStateSize (c, (ctrl_cs != null) ? ctrl_cs [c] : null),
229                                         control_pos));
230                         
231                         if (c.HasControls ()) {
232                                 foreach (Control child in c.Controls)
233                                         AddControl (child, control_pos + 1);
234                         }
235                 }
236
237                 int GetRenderSize (Control ctrl)
238                 {
239                         if (sizes == null)
240                                 return 0;
241
242                         object s = sizes [ctrl];
243                         return s == null ? 0 : (int) s;
244                 }
245
246                 static int GetViewStateSize (Control ctrl, object vs)
247                 {
248                         if (vs == null)
249                                 return 0;
250
251                         StringWriter sr = new StringWriter ();
252                         LosFormatter fmt = new LosFormatter ();
253                         fmt.Serialize (sr, vs);
254                         return sr.GetStringBuilder ().Length;
255                 }
256
257                 public void AddCookie (string name, string value)
258                 {
259                         cookie_data.Enqueue (new NameValueTraceData (name, value));
260                 }
261
262                 public void AddHeader (string name, string value)
263                 {
264                         header_data.Enqueue (new NameValueTraceData (name, value));
265                 }
266
267                 public void AddServerVar (string name, string value)
268                 {
269                         servervar_data.Enqueue (new NameValueTraceData (name, value));
270                 }
271                 
272                 public void Render (HtmlTextWriter output)
273                 {
274                         output.AddAttribute ("id", "__asptrace");
275                         output.RenderBeginTag (HtmlTextWriterTag.Div);
276                         
277                         RenderStyleSheet (output);
278                         
279                         output.AddAttribute ("class", "tracecontent");
280                         output.RenderBeginTag (HtmlTextWriterTag.Span);
281                         
282                         RenderRequestDetails (output);
283                         RenderTraceInfo (output);
284                         RenderControlTree (output);
285                         RenderCookies (output);
286                         RenderHeaders (output);
287                         RenderServerVars (output);
288                         
289                         output.RenderEndTag ();
290                         output.RenderEndTag ();
291                 }
292                 
293                 void RenderRequestDetails (HtmlTextWriter output)
294                 {
295                         Table table = CreateTable ();
296                         
297                         table.Rows.Add (AltRow ("Request Details:"));
298                         table.Rows.Add (InfoRow2 ("Session Id:", session_id,
299                                                         "Request Type", request_type));
300                         table.Rows.Add (InfoRow2 ("Time of Request:", request_time.ToString (),
301                                                         "State Code:", status_code.ToString ()));
302                         table.Rows.Add (InfoRow2 ("Request Encoding:", request_encoding.EncodingName,
303                                                    "Response Encoding:", response_encoding.EncodingName));           
304                         table.RenderControl (output);
305                 }
306                 
307                 void RenderTraceInfo (HtmlTextWriter output)
308                 {
309                         Table table = CreateTable ();
310                         
311                         table.Rows.Add (AltRow ("Trace Information"));
312                         table.Rows.Add (SubHeadRow ("Category", "Message", "From First(s)", "From Lasts(s)"));
313                         
314                         int pos = 0;
315                         IEnumerable<InfoTraceData> enumerable = info;
316
317                         if (TraceMode == TraceMode.SortByCategory) {
318                                 List<InfoTraceData> list = new List<InfoTraceData> (info);
319                                 list.Sort (delegate (InfoTraceData x, InfoTraceData y) { return String.Compare (x.Category, y.Category, StringComparison.Ordinal); });
320                                 enumerable = list;
321                         }
322
323                         foreach (InfoTraceData i in enumerable)
324                                 RenderTraceInfoRow (table, i, pos++);
325                         table.RenderControl (output);
326                 }
327                 
328                 void RenderControlTree (HtmlTextWriter output)
329                 {
330                         Table table = CreateTable ();
331                         
332                         int page_vs_size = page == null ? 0 : GetViewStateSize (page, page.GetSavedViewState ());
333                         table.Rows.Add (AltRow ("Control Tree"));
334                         table.Rows.Add (SubHeadRow ("Control Id", "Type",
335                                                 "Render Size Bytes (including children)",
336                                                 String.Format ("ViewState Size (total: {0} bytes)(excluding children)",
337                                                                 page_vs_size)
338                                                 ,"ControlState Size (excluding children)"
339                                                         ));
340                         
341                         int pos = 0;
342                         foreach (ControlTraceData r in control_data)
343                                 RenderControlTraceDataRow (table, r, pos++);
344                         table.RenderControl (output);
345                 }
346
347                 void RenderControlTraceDataRow (Table table, ControlTraceData r, int pos)
348                 {
349                         if (r == null)
350                                 return;
351                         
352                         int depth = r.Depth;
353                         string prefix = String.Empty;
354                         for (int i=0; i<depth; i++)
355                                 prefix += "&nbsp;&nbsp;&nbsp;&nbsp;";
356                         RenderAltRow (table, pos, prefix + r.ControlId,
357                                       r.Type.ToString (), r.RenderSize.ToString (),
358                                       r.ViewstateSize.ToString (), r.ControlstateSize.ToString ());
359                 }
360                 
361                 void RenderCookies (HtmlTextWriter output)
362                 {
363                         Table table = CreateTable ();
364                         
365                         table.Rows.Add (AltRow ("Cookies Collection"));
366                         table.Rows.Add (SubHeadRow ("Name", "Value", "Size"));
367                         
368                         int pos = 0;
369                         foreach (NameValueTraceData r in cookie_data)
370                                 RenderCookieDataRow (table, r, pos++);
371                         
372                         table.RenderControl (output);
373                 }
374
375                 void RenderCookieDataRow (Table table, NameValueTraceData r, int pos)
376                 {
377                         if (r == null)
378                                 return;
379                         
380                         int length = r.Name.Length + (r.Value == null ? 0 : r.Value.Length);
381                         RenderAltRow (table, pos++, r.Name, r.Value, length.ToString ());
382                 }
383                 
384                 void RenderHeaders (HtmlTextWriter output)
385                 {
386                         Table table = CreateTable ();
387                         
388                         table.Rows.Add (AltRow ("Headers Collection"));
389                         table.Rows.Add (SubHeadRow ("Name", "Value"));
390                         
391                         int pos = 0;
392                         foreach (NameValueTraceData r in header_data)
393                                 RenderAltRow (table, pos++, r.Name, r.Value);
394                         table.RenderControl (output);
395                 }
396                 
397                 void RenderServerVars (HtmlTextWriter output)
398                 {
399                         Table table = CreateTable ();
400                         
401                         table.Rows.Add (AltRow ("Server Variables"));
402                         table.Rows.Add (SubHeadRow ("Name", "Value"));
403                         
404                         int pos = 0;
405                         foreach (NameValueTraceData r in servervar_data)
406                                 RenderAltRow (table, pos++, r.Name, r.Value);
407                         table.RenderControl (output);
408                 }
409
410                 internal static TableRow AltRow (string title)
411                 {
412                         TableRow row = new TableRow ();
413                         TableHeaderCell header = new TableHeaderCell ();
414                         header.CssClass = "alt";
415                         header.HorizontalAlign = HorizontalAlign.Left;
416                         header.Attributes [" colspan"] = "10";
417                         header.Text = "<h3><b>" + title + "</b></h3>";
418
419                         row.Cells.Add (header);
420                         return row;
421                 }
422                 
423                 void RenderTraceInfoRow (Table table, InfoTraceData i, int pos)
424                 {
425                         if (i == null)
426                                 return;
427                         
428                         string open, close;
429                         open = close = String.Empty;
430                         if ((bool) i.IsWarning) {
431                                 open = "<span style=\"color:red\">";
432                                 close = "</span>";
433                         }
434
435                         string t1, t2;
436                         if (i.TimeSinceFirst == 0) {
437                                 t1 = t2 = String.Empty;
438                         } else
439                         {
440                                 t1 = i.TimeSinceFirst.ToString ("0.000000");
441                                 if (i.TimeSinceLast >= 0.1)
442                                         t2 = "<span style=\"color:red;font-weight:bold\">" + i.TimeSinceLast.ToString ("0.000000") + "</span>";
443                                 else
444                                         t2 = i.TimeSinceLast.ToString ("0.000000");
445                         }
446                         
447                         RenderAltRow (table, pos, open + (string) i.Category + close,
448                                       open + (string) i.Message + close, t1, t2);
449                 }
450            
451                 internal static TableRow SubHeadRow (params string[] cells)
452                 {
453                         TableRow row = new TableRow ();
454                         foreach (string s in cells) {
455                                 TableHeaderCell cell = new TableHeaderCell ();
456                                 cell.Text = s;
457                                 row.Cells.Add (cell);
458                         }
459                         
460                         row.CssClass = "subhead";
461                         row.HorizontalAlign = HorizontalAlign.Left;
462                         
463                         return row;
464                 }
465                 
466                 internal static TableRow RenderAltRow (Table table, int pos, params string[] cells)
467                 {
468                         TableRow row = new TableRow ();
469                         foreach (string s in cells) {
470                                 TableCell cell = new TableCell ();
471                                 cell.Text = s;
472                                 row.Cells.Add (cell);
473                    }
474                         
475                         if ((pos % 2) != 0)
476                                 row.CssClass = "alt";
477                         
478                         table.Rows.Add (row);
479                         return row;
480                 }
481            
482                 TableRow InfoRow2 (string title1, string info1, string title2, string info2)
483                 {
484                         TableRow row = new TableRow ();
485                         TableHeaderCell header1 = new TableHeaderCell ();
486                         TableHeaderCell header2 = new TableHeaderCell ();
487                         TableCell cell1 = new TableCell ();
488                         TableCell cell2 = new TableCell ();
489                         
490                         header1.Text = title1;
491                         header2.Text = title2;
492                         cell1.Text = info1;
493                         cell2.Text = info2;
494                         
495                         row.Cells.Add (header1);
496                         row.Cells.Add (cell1);
497                         row.Cells.Add (header2);
498                         row.Cells.Add (cell2);
499
500                         row.HorizontalAlign = HorizontalAlign.Left;
501                         
502                         return row;
503                 }
504                 
505                 internal static Table CreateTable ()
506                 {
507                         Table table = new Table ();
508                         
509                         table.Width = Unit.Percentage (100);
510                         table.CellSpacing = 0;
511                         table.CellPadding = 0;
512                         
513                         return table;
514                 }
515                 
516                 internal static void RenderStyleSheet (HtmlTextWriter o)
517                 {
518                         o.WriteLine ("<style type=\"text/css\">");
519                         o.Write ("span.tracecontent { background-color:white; ");
520                         o.WriteLine ("color:black;font: 10pt verdana, arial; }");
521                         o.Write ("span.tracecontent table { font: 10pt verdana, ");
522                         o.WriteLine ("arial; cellspacing:0; cellpadding:0; margin-bottom:25}");
523                         o.WriteLine ("span.tracecontent tr.subhead { background-color:cccccc;}");
524                         o.WriteLine ("span.tracecontent th { padding:0,3,0,3 }");
525                         o.WriteLine ("span.tracecontent th.alt { background-color:black; color:white; padding:3,3,2,3; }");
526                         o.WriteLine ("span.tracecontent td { padding:0,3,0,3 }");
527                         o.WriteLine ("span.tracecontent tr.alt { background-color:eeeeee }");
528                         o.WriteLine ("span.tracecontent h1 { font: 24pt verdana, arial; margin:0,0,0,0}");
529                         o.WriteLine ("span.tracecontent h2 { font: 18pt verdana, arial; margin:0,0,0,0}");
530                         o.WriteLine ("span.tracecontent h3 { font: 12pt verdana, arial; margin:0,0,0,0}");
531                         o.WriteLine ("span.tracecontent th a { color:darkblue; font: 8pt verdana, arial; }");
532                         o.WriteLine ("span.tracecontent a { color:darkblue;text-decoration:none }");
533                         o.WriteLine ("span.tracecontent a:hover { color:darkblue;text-decoration:underline; }");
534                         o.WriteLine ("span.tracecontent div.outer { width:90%; margin:15,15,15,15}");
535                         o.Write ("span.tracecontent table.viewmenu td { background-color:006699; ");
536                         o.WriteLine ("color:white; padding:0,5,0,5; }");
537                         o.WriteLine ("span.tracecontent table.viewmenu td.end { padding:0,0,0,0; }");
538                         o.WriteLine ("span.tracecontent table.viewmenu a {color:white; font: 8pt verdana, arial; }");
539                         o.WriteLine ("span.tracecontent table.viewmenu a:hover {color:white; font: 8pt verdana, arial; }");
540                         o.WriteLine ("span.tracecontent a.tinylink {color:darkblue; font: 8pt verdana, ");
541                         o.WriteLine ("arial;text-decoration:underline;}");
542                         o.WriteLine ("span.tracecontent a.link {color:darkblue; text-decoration:underline;}");
543                         o.WriteLine ("span.tracecontent div.buffer {padding-top:7; padding-bottom:17;}");
544                         o.WriteLine ("span.tracecontent .small { font: 8pt verdana, arial }");
545                         o.WriteLine ("span.tracecontent table td { padding-right:20 }");
546                         o.WriteLine ("span.tracecontent table td.nopad { padding-right:5 }");
547                         o.WriteLine ("</style>");
548                 }
549         }
550 }
551