// Copyright (c) 2008, NTT DATA Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Diagnostics;
using System.Text;

namespace TERASOLUNA.Fw.Common.Logging.TraceSourceLog
{
    /// <summary>
    /// <see cref="ITraceSourceLog"/> を実装したログ出力クラスです。
    /// <see cref="TraceSource"/>を使ってログを出力します。
    /// </summary>
	public class TraceSourceLogger : ITraceSourceLog
	{
        /// <summary>
        /// イベントIDのデフォルト値です。
        /// </summary>
        private const int DEFAULT_EVENT_ID = 0;
      
         /// <summary>
        /// メッセージ本体を生成するためのフォーマットです。
        /// </summary>
        /// <remarks>
        /// この定数の値は "{0} {1:yyyy-MM-dd HH:mm:ss,fff} [{2}] ({3}) - {4}" です。
        /// </remarks>
        private static readonly string BODY_MESSAGE_FORMAT = "{0} {1:yyyy-MM-dd HH:mm:ss,fff} [{2}] ({3}) - {4} ";

        /// <summary>
        /// 例外メッセージを生成するためのフォーマットです。
        /// </summary>
        /// <remarks>
        /// この定数の値は "&lt;{0} - {1}&gt;" です。
        /// </remarks>
        private static readonly string EXCEPTION_MESSAGE_FORMAT = "<{0} - {1}>"; 
        
        /// <summary>
        /// 内部例外メッセージを生成するためのフォーマットです。
        /// </summary>
        /// <remarks>
        /// この定数の値は "{0}: {1}" です。
        /// </remarks>
        private static readonly string INNER_EXCEPTION_MESSAGE_FORMAT = "{0} : {1}"; 

        /// <summary>
		/// クラス名。
        /// </summary>
        /// <remarks>
        /// デフォルトの値は、 null です。
        /// </remarks>
		private string _className = null;
		
        /// <summary>
        /// トレースソース。
        /// </summary>
        /// <remarks>
        /// デフォルトの値は null です。
        /// </remarks>
        private TraceSource _traceSource = null;

        /// <summary>
        /// ログレベル。
        /// </summary>
        /// <remarks>
        /// デフォルトの値は <seealso cref="LogLevel.OFF"/> です。
        /// </remarks>
        private LogLevel _logLevel = LogLevel.OFF;

        /// <summary>
        /// イベントIDのデフォルト値を取得します。
        /// </summary>
        /// <value>
        /// イベント ID 。
        /// </value>
        /// <remarks>
        /// デフォルトの値は、 0 です。
        /// </remarks>
        protected virtual int DefaultEventId
        {
            get { return DEFAULT_EVENT_ID; }
        }

        /// <summary>
        /// メッセージ本体を生成するためのフォーマットを取得します。
        /// </summary>
        /// <value>
        /// メッセージ本体を生成するためのフォーマット。
        /// </value>
        /// <remarks>
        /// デフォルトの値は、"{0} {1:yyyy-MM-dd HH:mm:ss,fff} [{2}] ({3}) - {4} " です。
        /// </remarks>
        protected virtual string BodyMessageFormat
        {
            get { return BODY_MESSAGE_FORMAT; }
        }

        /// <summary>
        /// 例外メッセージを生成するためのフォーマットを取得します。
        /// </summary>
        /// <value>
        /// 例外メッセージのフォーマット。
        /// </value>
        /// <remarks>
        /// デフォルトの値は、"&lt;{0} - {1}&gt;"です。
        /// </remarks>
        protected virtual string ExceptionMessageFormat
        {
            get { return EXCEPTION_MESSAGE_FORMAT; }
        }

        /// <summary>
        /// 内部例外メッセージを生成するためのフォーマットを取得します。
        /// </summary>
        /// <value>
        /// 内部例外メッセージのフォーマット。
        /// </value>
        /// <remarks>
        /// デフォルトの値は、"{0}: {1}"です。
        /// </remarks>
        protected virtual string InnerExceptionMessageFormat
        {
            get { return INNER_EXCEPTION_MESSAGE_FORMAT; }
        }

        /// <summary>
        /// クラス名を取得または設定します。
        /// </summary>
        /// <value>
        /// クラス名。
        /// </value>
        /// <remarks>
        /// デフォルトの値は、null です。
        /// </remarks>
        protected string ClassName
        {
            get { return _className; }
            set { _className = value; }
        }

        /// <summary>
        /// トレースソースを取得または設定します。
        /// </summary>
        /// <value>
        /// トレースソース。
        /// </value>
        /// <remarks>
        /// デフォルトの値は、null です。
        /// </remarks>
        protected TraceSource CurrentTraceSource
        {
            get { return _traceSource; }
            set { _traceSource = value; }
        }

        /// <summary>
        /// ログレベルを取得または設定します。
        /// </summary>
        /// <value>
        /// ログレベル。
        /// </value>
        /// <remarks>
        /// デフォルトの値は、 <seealso cref="LogLevel.OFF"/> です。
        /// </remarks>
        protected LogLevel CurrentLogLevel
        {
            get { return _logLevel; }
            set { _logLevel = value; }
        }

        /// <summary>
        /// Trace レベルのログ処理が現在有効かどうかチェックします。
        /// </summary>
        /// <remarks>
        /// ログレベルが trace 以上の場合に(String の連結のような) 
        /// 重い処理を行わないようにこのメソッドを呼んで(チェックして)ください。
        /// </remarks>
        public bool IsTraceEnabled
		{
			get { return IsLevelEnabled(LogLevel.TRACE); }
		}

        /// <summary>
        /// Debug レベルのログ処理が現在有効かどうかチェックします。
        /// </summary>
        /// <remarks>
        /// ログレベルが debug 以上の場合に(String の連結のような) 
        /// 重い処理を行わないようにこのメソッドを呼んで(チェックして)ください。
        /// </remarks>
        public bool IsDebugEnabled
		{
			get { return IsLevelEnabled(LogLevel.DEBUG); }
		}

        /// <summary>
        /// Info レベルのログ処理が現在有効かどうかチェックします。
        /// </summary>
        /// <remarks>
        /// ログレベルが Info 以上の場合に(String の連結のような) 
        /// 重い処理を行わないようにこのメソッドを呼んで(チェックして)ください。
        /// </remarks>
        public bool IsInfoEnabled
		{
			get { return IsLevelEnabled(LogLevel.INFO); }
		}

        /// <summary>
        /// Warn レベルのログ処理が現在有効かどうかチェックします。
        /// </summary>
        /// <remarks>
        /// ログレベルが Warn 以上の場合に(String の連結のような) 
        /// 重い処理を行わないようにこのメソッドを呼んで(チェックして)ください。
        /// </remarks>
        public bool IsWarnEnabled
		{
			get { return IsLevelEnabled(LogLevel.WARN); }
		}

        /// <summary>
        /// Error レベルのログ処理が現在有効かどうかチェックします。
        /// </summary>
        /// <remarks>
        /// ログレベルが Error 以上の場合に(String の連結のような) 
        /// 重い処理を行わないようにこのメソッドを呼んで(チェックして)ください。
        /// </remarks>
        public bool IsErrorEnabled
		{
			get { return IsLevelEnabled(LogLevel.ERROR); }
		}

        /// <summary>
        /// Fatal レベルのログ処理が現在有効かどうかチェックします。
        /// </summary>
        /// <remarks>
        /// ログレベルが Fatal 以上の場合に(String の連結のような) 
        /// 重い処理を行わないようにこのメソッドを呼んで(チェックして)ください。
        /// </remarks>
        public bool IsFatalEnabled
		{
			get { return IsLevelEnabled(LogLevel.FATAL); }
		}

        /// <summary>
        /// コンストラクタです。
        /// </summary>
        /// <param name="className">クラス名。</param>
        /// <param name="sourceName">トレースソースの名前。</param>
        /// <exception cref="ArgumentNullException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="className"/> が null 参照です。
        /// </item>
        /// <item>
        /// <paramref name="sourceName"/> が null 参照です。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="ArgumentException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="className"/> が空文字です。
        /// </item>
        /// <item>
        /// <paramref name="sourceName"/> が空文字です。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="TerasolunaException">
        /// <paramref name="sourceLevel"/> が不正です。
        /// &lt;switches&gt; タグの子要素（add 要素）の value 属性には
        /// Off, Critical, Error, Warning, Information, Verbose, All のいずれかを設定してください。
        /// </exception>
        /// <exception cref="System.Configuration.ConfigurationErrorsException">
        /// 構成ファイルの設定が不正です。
        /// </exception>
        public TraceSourceLogger(string className, string sourceName)
        {
            // 入力チェック
            if (className == null)
            {
                throw new ArgumentNullException("className");
            }

            if (className.Length == 0)
            {
                throw new ArgumentException(string.Format(
                    Properties.Resources.E_EMPTY_STRING, "className"));
            }

            if (sourceName == null)
            {
                throw new ArgumentNullException("sourceName");
            }

            if (sourceName.Length == 0)
            {
                throw new ArgumentException(string.Format(
                    Properties.Resources.E_EMPTY_STRING, "sourceName"));
            }

            _className = className;
            _traceSource = new TraceSource(sourceName);
            _logLevel = GetLogLevel(_traceSource.Switch.Level);
        }

        /// <summary>
        /// コンストラクタです。
        /// </summary>
        /// <param name="classType">クラスのタイプ。</param>
        /// <param name="sourceName">トレースソースの名前。</param>
        /// <exception cref="ArgumentNullException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="className"/> が null 参照です。
        /// </item>
        /// <item>
        /// <paramref name="sourceName"/> が null 参照です。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="sourceName"/> が空文字です。
        /// </exception>
        /// <exception cref="TerasolunaException">
        /// <paramref name="sourceLevel"/> が不正です。
        /// &lt;switches&gt; タグの子要素（add 要素）の value 属性には
        /// Off, Critical, Error, Warning, Information, Verbose, All のいずれかを設定してください。
        /// </exception>
        /// <exception cref="System.Configuration.ConfigurationErrorsException">
        /// 構成ファイルの設定が不正です。
        /// </exception>
        public TraceSourceLogger(Type classType, string sourceName)
        {
            // 入力チェック
            if (classType == null)
            {
                throw new ArgumentNullException("classType");
            }

            if (sourceName == null)
            {
                throw new ArgumentNullException("sourceName");
            }

            if (sourceName.Length == 0)
            {
                throw new ArgumentException(string.Format(
                    Properties.Resources.E_EMPTY_STRING, "sourceName"));
            }

            _className = classType.FullName;
            _traceSource = new TraceSource(sourceName);
            _logLevel = GetLogLevel(_traceSource.Switch.Level);
        }

        /// <summary>
        /// Trace ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        public virtual void Trace(object message)
        {
            if (IsTraceEnabled)
            {
                Write(LogLevel.TRACE, message);
            }
        }

        /// <summary>
        /// Trace レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        public virtual void Trace(object message, Exception ex)
        {
            if (IsTraceEnabled)
            {
                Write(LogLevel.TRACE, message, ex);
            }
        }

        /// <summary>
        /// Trace ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Trace(object message, int eventId)
        {
            if (IsTraceEnabled)
            {
                Write(LogLevel.TRACE, message, eventId);
            }
        }

        /// <summary>
        /// Trace レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Trace(object message, Exception ex, int eventId)
        {
            if (IsTraceEnabled)
            {
                Write(LogLevel.TRACE, message, ex, eventId);
            }
        }

        /// <summary>
        /// Debug ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        public virtual void Debug(object message)
        {
            if (IsDebugEnabled)
            {
                Write(LogLevel.DEBUG, message);
            }
        }

        /// <summary>
        /// Debug レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        public virtual void Debug(object message, Exception ex)
        {
            if (IsDebugEnabled)
            {
                Write(LogLevel.DEBUG, message, ex);
            }
        }

        /// <summary>
        /// Debug ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Debug(object message, int eventId)
        {
            if (IsDebugEnabled)
            {
                Write(LogLevel.DEBUG, message, eventId);
            }
        }

        /// <summary>
        /// Debug レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Debug(object message, Exception ex, int eventId)
        {
            if (IsDebugEnabled)
            {
                Write(LogLevel.DEBUG, message, ex, eventId);
            }
        }

        /// <summary>
        /// Info ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>		
        public virtual void Info(object message)
        {
            if (IsInfoEnabled)
            {
                Write(LogLevel.INFO, message);
            }
        }

        /// <summary>
        /// Info レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        public virtual void Info(object message, Exception ex)
        {
            if (IsInfoEnabled)
            {
                Write(LogLevel.INFO, message, ex);
            }
        }

        /// <summary>
        /// Info ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Info(object message, int eventId)
        {
            if (IsInfoEnabled)
            {
                Write(LogLevel.INFO, message, eventId);
            }
        }

        /// <summary>
        /// Info レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Info(object message, Exception ex, int eventId)
        {
            if (IsInfoEnabled)
            {
                Write(LogLevel.INFO, message, ex, eventId);
            }
        }

        /// <summary>
        /// Warn ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>	
        public virtual void Warn(object message)
        {
            if (IsWarnEnabled)
            {
                Write(LogLevel.WARN, message);
            }
        }

        /// <summary>
        /// Warn レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        public virtual void Warn(object message, Exception ex)
        {
            if (IsWarnEnabled)
            {
                Write(LogLevel.WARN, message, ex);
            }
        }

        /// <summary>
        /// Warn ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Warn(object message, int eventId)
        {
            if (IsWarnEnabled)
            {
                Write(LogLevel.WARN, message, eventId);
            }
        }

        /// <summary>
        /// Warn レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Warn(object message, Exception ex, int eventId)
        {
            if (IsWarnEnabled)
            {
                Write(LogLevel.WARN, message, ex, eventId);
            }
        }

        /// <summary>
        /// Error ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        public virtual void Error(object message)
        {
            if (IsErrorEnabled)
            {
                Write(LogLevel.ERROR, message);
            }
        }

        /// <summary>
        /// Error レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        public virtual void Error(object message, Exception ex)
        {
            if (IsErrorEnabled)
            {
                Write(LogLevel.ERROR, message, ex);
            }
        }

        /// <summary>
        /// Error ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Error(object message, int eventId)
        {
            if (IsErrorEnabled)
            {
                Write(LogLevel.ERROR, message, eventId);
            }
        }

        /// <summary>
        /// Error レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Error(object message, Exception ex, int eventId)
        {
            if (IsErrorEnabled)
            {
                Write(LogLevel.ERROR, message, ex, eventId);
            }
        }


        /// <summary>
        /// Fatal ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>	
        public virtual void Fatal(object message)
        {
            if (IsFatalEnabled)
            {
                Write(LogLevel.FATAL, message);
            }
        }

        /// <summary>
        /// Fatal レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        public virtual void Fatal(object message, Exception ex)
        {
            if (IsFatalEnabled)
            {
                Write(LogLevel.FATAL, message, ex);
            }
        }

        /// <summary>
        /// Fatal ログレベルでメッセージをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Fatal(object message, int eventId)
        {
            if (IsFatalEnabled)
            {
                Write(LogLevel.FATAL, message, eventId);
            }
        }

        /// <summary>
        /// Fatal レベルでエラーをログ出力します。
        /// </summary>
        /// <param name="message">ログ出力するメッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        /// <param name="eventId">イベントの数値識別子。</param>
        public virtual void Fatal(object message, Exception ex, int eventId)
        {
            if (IsFatalEnabled)
            {
                Write(LogLevel.FATAL, message, ex, eventId);
            }
        }

        /// <summary>
        /// 引数で与えられた <see cref="SourceLevels"/> に対応した <see cref="LogLevel"/> を返します。
        /// </summary>
        /// <param name="sourceLevel">トレースメッセージのレベル。</param>
        /// <returns><see cref="LogLevel"/> 。</returns>
        /// <exception cref="TerasolunaException">
        /// <paramref name="sourceLevel"/> が不正です。
        /// </exception>
        protected static LogLevel GetLogLevel(SourceLevels sourceLevel)
        {
            switch (sourceLevel)
            {
                case SourceLevels.Critical:
                    return LogLevel.FATAL;

                case SourceLevels.Error:
                    return LogLevel.ERROR;

                case SourceLevels.Warning:
                    return LogLevel.WARN;

                case SourceLevels.Information:
                    return LogLevel.INFO;

                case SourceLevels.Verbose:
                    return LogLevel.DEBUG;

                case SourceLevels.All:
                    return LogLevel.TRACE;

                case SourceLevels.Off:
                    return LogLevel.OFF;

                default:
                    throw new TerasolunaException(string.Format(
                        Properties.Resources.E_INVALID_ARGUMENT, "sourceLevel"));
            }
        }

        /// <summary>
        /// 引数で与えられたログレベルが有効な場合、true を返します。
        /// </summary>
        /// <param name="logLevel">ログレベル。</param>
        /// <returns>ログレベルが有効化どうかのbool値。</returns>
        protected virtual bool IsLevelEnabled(LogLevel logLevel)
        {
            return (logLevel <= _logLevel);
        }

        /// <summary>
        /// ログメッセージを出力します。
        /// </summary>
        /// <param name="logLevel">ログレベル。</param>
        /// <param name="message">メッセージ。</param>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="logLevel"/> は <seealso cref="LogLevel.OFF"/> です。
        /// </item>
        /// <item>
        /// <paramref name="logLevel"/> は不正です。
        /// </item>
        /// </list>
        /// </exception>
        protected virtual void Write(LogLevel logLevel, object message)
		{
            Write(logLevel, message, null, DEFAULT_EVENT_ID);
		}

        /// <summary>
        /// ログメッセージを出力します。
        /// </summary>
        /// <param name="logLevel">ログレベル。</param>
        /// <param name="message">メッセージ。</param>
        /// <param name="ex">ログ出力の原因となった例外。</param>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="logLevel"/> は <seealso cref="LogLevel.OFF"/> です。
        /// </item>
        /// <item>
        /// <paramref name="logLevel"/> は不正です。
        /// </item>
        /// </list>
        /// </exception>
        protected virtual void Write(LogLevel logLevel, object message, Exception ex)
        {
            Write(logLevel, message, ex, DEFAULT_EVENT_ID);
        }

        /// <summary>
        /// ログメッセージを出力します。
        /// </summary>
        /// <param name="logLevel">ログレベル。</param>
        /// <param name="message">メッセージ。</param>
        /// <param name="eventId">イベント ID 。</param>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="logLevel"/> は <seealso cref="LogLevel.OFF"/> です。
        /// </item>
        /// <item>
        /// <paramref name="logLevel"/> は不正です。
        /// </item>
        /// </list>
        /// </exception>
        protected virtual void Write(LogLevel logLevel, object message, int eventId)
        {
            Write(logLevel, message, null, eventId);
        }

        /// <summary>
        /// ログメッセージを出力します。
        /// </summary>
        /// <param name="logLevel">ログレベル。</param>
        /// <param name="message">メッセージ。</param>
        /// <param name="ex">例外クラスのインスタンス。</param>
        /// <param name="eventId">イベント ID 。</param>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <see cref="TraceEventType"/> は <seealso cref="LogLevel.OFF"/> に変換することができません。
        /// </item>
        /// <item>
        /// <paramref name="logLevel"/> は不正です。
        /// </item>
        /// </list>
        /// </exception>
        protected virtual void Write(LogLevel logLevel,
                           object message,
                           Exception ex,
                           int eventId)
        {
            TraceEventType eventType = GetTraceEventType(logLevel);
            
            string messageStr = CreateMessage(message, logLevel, ex);

            _traceSource.TraceEvent(eventType, eventId, messageStr);
            _traceSource.Flush();           				
		}

        /// <summary>
        /// 引数で与えられた<see cref="LogLevel"/>に対応した<see cref="TraceEventType"/>を返します。
        /// </summary>
        /// <param name="logLevel">ログレベル。</param>
        /// <returns><see cref="TraceEventType"/> 。</returns>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <see cref="TraceEventType"/> は <seealso cref="LogLevel.OFF"/> に変換することができません。
        /// </item>
        /// <item>
        /// <paramref name="logLevel"/> は不正です。
        /// </item>
        /// </list>
        /// </exception>
        protected virtual TraceEventType GetTraceEventType(LogLevel logLevel)
        {
            if (logLevel == LogLevel.OFF)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_INVALID_LOGLEVEL_ARGUMENT, "logLevel"));
            }

            switch (logLevel)
            {
                case LogLevel.TRACE:
                    return TraceEventType.Verbose;

                case LogLevel.DEBUG:
                    return TraceEventType.Verbose;

                case LogLevel.INFO:
                    return TraceEventType.Information;

                case LogLevel.WARN:
                    return TraceEventType.Warning;

                case LogLevel.ERROR:
                    return TraceEventType.Error;

                case LogLevel.FATAL:
                    return TraceEventType.Critical;

                default:
                    throw new TerasolunaException(string.Format(
                        Properties.Resources.E_INVALID_ARGUMENT, "logLevel"));
            }
        }
        
        /// <summary>
        /// 出力するログメッセージを生成します。
        /// </summary>
        /// <param name="message">メッセージ。</param>
        /// <param name="logLevel">ログレベル。</param>
        /// <param name="ex">例外クラスのインスタンス。</param>
        /// <returns>生成したログメッセージ。</returns>
        protected virtual string CreateMessage(object message, LogLevel logLevel, Exception ex)
        {
            StringBuilder strBuilder = new StringBuilder();

            strBuilder.AppendFormat(
                BodyMessageFormat,
                logLevel,
                DateTime.Now,
                System.Threading.Thread.CurrentThread.ManagedThreadId.ToString(),
                _className,
                message);
 
            if (ex != null)
            {
                strBuilder.AppendFormat(
                    ExceptionMessageFormat,
                    ex.GetType().FullName,
                    ex.Message);
                do
                {
                    if (ex.StackTrace != null)
                    {
                        strBuilder.Append(Environment.NewLine);
                        strBuilder.AppendFormat(
                            InnerExceptionMessageFormat,
                            ex.GetType().ToString(),
                            ex.Message);
                        strBuilder.Append(Environment.NewLine);
                        strBuilder.Append(ex.StackTrace);
                    }
                    ex = ex.InnerException;
                } while (ex != null);
            }

            return strBuilder.ToString();
        }
	}
}
