1: using System;
2: using System.Xml;
3: using System.Xml.Serialization;
4: using System.Text;
5: using System.IO;
6: using System.Collections;
7: using System.Collections.Specialized;
8: using System.Web;
9: using System.Web.SessionState;
10: using System.Diagnostics;
11: using System.Reflection;
12: using System.Runtime.Serialization.Formatters.Soap;
13: using Microsoft.ApplicationBlocks.ExceptionManagement;
14:
15: namespace Microsoft.Japan.Mcs.Utilities.ExceptionManagement
16: {
17: /// <summary>
18: /// Microsoft Exception Management Application Blockに取り込んで利用する、
19: /// カスタムの例外パブリッシャ。HTTP関連情報と共に、ローカルのログファイルへと
20: /// 出力する。ローカルログファイル名はweb.config内にてfilename属性により指定、
21: /// 無指定の場合には自動的に名前がつけられ、Cドライブ直下に保存される。
22: /// </summary>
23: public class TraceLogFilePublisher : IExceptionPublisher
24: {
25:
26: /// <summary>
27: /// デフォルトコンストラクタ。ExceptionManagerが利用する。
28: /// </summary>
29: public TraceLogFilePublisher()
30: {
31: }
32:
33: /// <summary>
34: /// 例外情報をHTTPの各種の情報と共にログファイルへ出力します。
35: /// </summary>
36: /// <param name="exception">発生した例外情報</param>
37: /// <param name="additionalInfo">追加情報</param>
38: /// <param name="configSettings">構成情報</param>
39: public void Publish(Exception exception, NameValueCollection additionalInfo, NameValueCollection configSettings)
40: {
41: StringBuilder strInfo = new StringBuilder();
42: strInfo.Append("\n\n***** TraceLogFilePublisher からのエラー情報 *****\n");
43:
44: #region DefaultPublisher でも出力している一般的なエラー情報(DefaultPublisherクラスから引用)
45:
46: #region Geberal Exception Information
47: // DefaultPublisher Information
48:
49: if (additionalInfo != null)
50: {
51: // Record General information.
52: strInfo.AppendFormat("\n" + "[General Information]");
53:
54: foreach (string i in additionalInfo)
55: {
56: strInfo.AppendFormat("\n{0}: {1}", i, additionalInfo.Get(i));
57: }
58: }
59: #endregion
60:
61: if (exception == null)
62: {
63: strInfo.Append("\n\nNo Exception.\n");
64: }
65: else
66: {
67: #region Loop through each exception class in the chain of exception objects
68: // Loop through each exception class in the chain of exception objects.
69: Exception currentException = exception; // Temp variable to hold InnerException object during the loop.
70: int intExceptionCount = 1; // Count variable to track the number of exceptions in the chain.
71: do
72: {
73: // Write title information for the exception object.
74: strInfo.AppendFormat("\n\n{0}) Exception Information\n{1}", intExceptionCount.ToString(), "");
75: strInfo.AppendFormat("\nException Type: {0}", currentException.GetType().FullName);
76:
77: #region Loop through the public properties of the exception object and record their value
78: // Loop through the public properties of the exception object and record their value.
79: PropertyInfo[] aryPublicProperties = currentException.GetType().GetProperties();
80: NameValueCollection currentAdditionalInfo;
81: foreach (PropertyInfo p in aryPublicProperties)
82: {
83: // Do not log information for the InnerException or StackTrace. This information is
84: // captured later in the process.
85: if (p.Name != "InnerException" && p.Name != "StackTrace")
86: {
87: if (p.GetValue(currentException, null) == null)
88: {
89: strInfo.AppendFormat("\n{0}: NULL", p.Name);
90: }
91: else
92: {
93: // Loop through the collection of AdditionalInformation if the exception type is a BaseApplicationException.
94: if (p.Name == "AdditionalInformation" && currentException is BaseApplicationException)
95: {
96: // Verify the collection is not null.
97: if (p.GetValue(currentException, null) != null)
98: {
99: // Cast the collection into a local variable.
100: currentAdditionalInfo = (NameValueCollection)p.GetValue(currentException, null);
101:
102: // Check if the collection contains values.
103: if (currentAdditionalInfo.Count > 0)
104: {
105: strInfo.Append("\nAdditionalInformation:");
106:
107: // Loop through the collection adding the information to the string builder.
108: for (int i = 0; i < currentAdditionalInfo.Count; i++)
109: {
110: strInfo.AppendFormat("\n{0}: {1}", currentAdditionalInfo.GetKey(i), currentAdditionalInfo[i]);
111: }
112: }
113: }
114: }
115: // Otherwise just right the ToString() value of the property.
116: else
117: {
118: strInfo.AppendFormat("\n{0}: {1}", p.Name, p.GetValue(currentException, null));
119: }
120: }
121: }
122: }
123: #endregion
124: #region Record the Exception StackTrace
125: // Record the StackTrace with separate label.
126: if (currentException.StackTrace != null)
127: {
128: strInfo.AppendFormat("\n" + "StackTrace Information" + "\n");
129: strInfo.AppendFormat("\n{0}", currentException.StackTrace);
130: }
131: #endregion
132:
133: // Reset the temp exception object and iterate the counter.
134: currentException = currentException.InnerException;
135: intExceptionCount++;
136: } while (currentException != null);
137: #endregion
138: }
139:
140: #endregion
141:
142: #region Web システム固有の情報を取得・出力するルーチン
143:
144: if (HttpContext.Current == null)
145: {
146: strInfo.Append("\n\n[HTTP Information]\nNo Information.\n");
147: }
148: else
149: {
150: strInfo.Append("\n\n[HTTP Information]\n");
151:
152: HttpRequest Request = HttpContext.Current.Request;
153:
154: if (Request != null)
155: {
156: // HTTP サーバ環境変数の出力
157: strInfo.Append("[HTTP ServerVariables (HTTPサーバ環境変数)]\n");
158: foreach (string key in Request.ServerVariables.AllKeys)
159: {
160: strInfo.Append(String.Format("{0} : {1}\n", key, Request.ServerVariables[key]));
161: }
162: strInfo.Append("\n");
163:
164: //HTTP リクエストヘッダの出力
165: strInfo.Append("[HTTP Request Headers (HTTPリクエストヘッダ)]\n");
166: foreach (string key in Request.Headers.AllKeys)
167: {
168: strInfo.Append(String.Format("{0} : {1}\n", key, Request.Headers[key]));
169: }
170: strInfo.Append("\n");
171:
172: //HTTP リクエストクッキー情報の出力
173: strInfo.Append("[HTTP Request Cookies (HTTPリクエストクッキー)]\n");
174: foreach (string key in Request.Cookies.AllKeys)
175: {
176: strInfo.Append(String.Format("{0} : {1}\n", key, Request.Cookies[key].Value));
177: }
178: strInfo.Append("\n");
179:
180: //HTTP クエリ文字列の出力
181: strInfo.Append("[HTTP Request QueryString (HTTPクエリ文字列)]\n");
182: foreach (string key in Request.QueryString.AllKeys)
183: {
184: strInfo.Append(String.Format("{0} : {1}\n", key, Request.QueryString[key]));
185: }
186: strInfo.Append("\n");
187:
188: //HTTP フォームデータの出力
189: strInfo.Append("[HTTP Request Form (HTTPフォーム)]\n");
190: foreach (string key in Request.Form.AllKeys)
191: {
192: strInfo.Append(String.Format("{0} : {1}\n", key, Request.Form[key]));
193: }
194: strInfo.Append("\n");
195: }
196: else
197: {
198: strInfo.Append("[HTTP Request Information]\nデータがありません。\n\n");
199: }
200:
201: HttpResponse Response = HttpContext.Current.Response;
202:
203: if (Response != null)
204: {
205: // HTTP レスポンスステータス情報の出力
206: strInfo.Append("[HTTP Response Status (HTTPレスポンス状態)]\n");
207: strInfo.Append(String.Format("Status : {0}\n", Response.Status));
208: strInfo.Append(String.Format("Status Code : {0}\n", Response.StatusCode));
209: strInfo.Append("\n");
210:
211: // HTTP レスポンスクッキー情報の出力
212: strInfo.Append("[HTTP Response Cookies (HTTPレスポンスクッキー)]\n");
213: foreach (string key in Response.Cookies.AllKeys)
214: {
215: strInfo.Append(String.Format("{0} : {1}\n", key, Response.Cookies[key].Value));
216: }
217: strInfo.Append("\n");
218: }
219: else
220: {
221: strInfo.Append("[HTTP Response Information]\nデータがありません。\n\n");
222: }
223:
224: HttpSessionState Session = HttpContext.Current.Session;
225:
226: if (Session != null)
227: {
228: // HTTP Session内に含まれている情報の出力
229: strInfo.Append("[HTTP Session Object (Sessionオブジェクト内の情報)]\n");
230:
231: foreach (string key in Session.Keys)
232: {
233: // Session内には任意のオブジェクトが格納されるが、その中身をテキスト化するには
234: // ToString()では不十分。XmlSerializerクラスを利用して、XMLテキスト化する。
235: object obj = Session[key];
236: string xml = null;
237: try
238: {
239: TextWriter writer = new StringWriter();
240: XmlSerializer serializer = new XmlSerializer(obj.GetType());
241: serializer.Serialize(writer, obj);
242: xml = writer.ToString();
243: }
244: catch (Exception)
245: {
246: MemoryStream memstream = new MemoryStream();
247: SoapFormatter formatter = new SoapFormatter();
248: formatter.Serialize(memstream, obj);
249: StreamReader reader = new StreamReader(memstream);
250: reader.BaseStream.Seek(0, SeekOrigin.Begin);
251: xml = reader.ReadToEnd();
252: }
253: strInfo.Append(String.Format("{0}({1}) : \n{2}\n", key, obj.GetType().Name, xml));
254: }
255: strInfo.Append("\n");
256: }
257: else
258: {
259: strInfo.Append("[HTTP Session Information]\nデータがありません。\n\n");
260: }
261: }
262:
263: #endregion
264:
265: #region ローカルログファイルへの出力処理
266:
267: #region web.config からの出力ファイル名の取得
268:
269: string filename = null;
270:
271: if (configSettings["fileName"] != null &&
272: configSettings["fileName"].Length > 0)
273: {
274: filename = configSettings["fileName"];
275: }
276: else
277: {
278: // ファイル名の指定がない場合には、アプリケーションドメイン名を利用したファイル名で出力する
279: string applicationName = AppDomain.CurrentDomain.FriendlyName;
280: applicationName = applicationName.Replace("/", "_");
281: filename = @"C:\" + applicationName + "_tracelog.txt";
282: }
283: #endregion
284:
285: using (System.Threading.Mutex m = new System.Threading.Mutex(false, this.GetType().FullName + ".FileWrite"))
286: {
287: m.WaitOne();
288:
289: // 既存ファイルがある場合はアペンド扱い
290: using (StreamWriter sw = new StreamWriter(filename, true, System.Text.Encoding.Default))
291: {
292: sw.Write(strInfo.ToString());
293: sw.Close();
294: }
295:
296: m.ReleaseMutex();
297: }
298: #endregion
299:
300: }
301: }
302: }