|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
namespace System.Diagnostics {
using System.Runtime.Remoting;
using System;
using System.Security.Permissions;
using System.IO;
using System.Collections;
using System.Runtime.CompilerServices;
using Encoding = System.Text.Encoding;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
using System.Diagnostics.CodeAnalysis;
// LogMessageEventHandlers are triggered when a message is generated which is
// "on" per its switch.
//
// By default, the debugger (if attached) is the only event handler.
// There is also a "built-in" console device which can be enabled
// programatically, by registry (specifics....) or environment
// variables.
[Serializable]
[HostProtection(Synchronization=true, ExternalThreading=true)]
internal delegate void LogMessageEventHandler(LoggingLevels level, LogSwitch category,
String message,
StackTrace location);
// LogSwitchLevelHandlers are triggered when the level of a LogSwitch is modified
// NOTE: These are NOT triggered when the log switch setting is changed from the
// attached debugger.
//
[Serializable]
internal delegate void LogSwitchLevelHandler(LogSwitch ls, LoggingLevels newLevel);
internal static class Log
{
// Switches allow relatively fine level control of which messages are
// actually shown. Normally most debugging messages are not shown - the
// user will typically enable those which are relevant to what is being
// investigated.
//
// An attached debugger can enable or disable which messages will
// actually be reported to the user through the COM+ debugger
// services API. This info is communicated to the runtime so only
// desired events are actually reported to the debugger.
internal static Hashtable m_Hashtable;
private static volatile bool m_fConsoleDeviceEnabled;
private static LogMessageEventHandler _LogMessageEventHandler;
private static volatile LogSwitchLevelHandler _LogSwitchLevelHandler;
private static Object locker;
// Constant representing the global switch
public static readonly LogSwitch GlobalSwitch;
static Log()
{
m_Hashtable = new Hashtable();
m_fConsoleDeviceEnabled = false;
//pConsole = null;
//iNumOfMsgHandlers = 0;
//iMsgHandlerArraySize = 0;
locker = new Object();
// allocate the GlobalSwitch object
GlobalSwitch = new LogSwitch ("Global", "Global Switch for this log");
GlobalSwitch.MinimumLevel = LoggingLevels.ErrorLevel;
}
public static void AddOnLogMessage(LogMessageEventHandler handler)
{
lock (locker)
_LogMessageEventHandler =
(LogMessageEventHandler) MulticastDelegate.Combine(_LogMessageEventHandler, handler);
}
public static void RemoveOnLogMessage(LogMessageEventHandler handler)
{
lock (locker)
_LogMessageEventHandler =
(LogMessageEventHandler) MulticastDelegate.Remove(_LogMessageEventHandler, handler);
}
public static void AddOnLogSwitchLevel(LogSwitchLevelHandler handler)
{
lock (locker)
_LogSwitchLevelHandler =
(LogSwitchLevelHandler) MulticastDelegate.Combine(_LogSwitchLevelHandler, handler);
}
public static void RemoveOnLogSwitchLevel(LogSwitchLevelHandler handler)
{
lock (locker)
_LogSwitchLevelHandler =
(LogSwitchLevelHandler) MulticastDelegate.Remove(_LogSwitchLevelHandler, handler);
}
internal static void InvokeLogSwitchLevelHandlers (LogSwitch ls, LoggingLevels newLevel)
{
LogSwitchLevelHandler handler = _LogSwitchLevelHandler;
if (handler != null)
handler(ls, newLevel);
}
// Property to Enable/Disable ConsoleDevice. Enabling the console device
// adds the console device as a log output, causing any
// log messages which make it through filters to be written to the
// application console. The console device is enabled by default if the
// ??? registry entry or ??? environment variable is set.
public static bool IsConsoleEnabled
{
get { return m_fConsoleDeviceEnabled; }
set { m_fConsoleDeviceEnabled = value; }
}
// Generates a log message. If its switch (or a parent switch) allows the
// level for the message, it is "broadcast" to all of the log
// devices.
//
public static void LogMessage(LoggingLevels level, String message)
{
LogMessage (level, GlobalSwitch, message);
}
// Generates a log message. If its switch (or a parent switch) allows the
// level for the message, it is "broadcast" to all of the log
// devices.
//
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
public static void LogMessage(LoggingLevels level, LogSwitch logswitch, String message)
{
if (logswitch == null)
throw new ArgumentNullException ("LogSwitch");
if (level < 0)
throw new ArgumentOutOfRangeException("level", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
Contract.EndContractBlock();
// Is logging for this level for this switch enabled?
if (logswitch.CheckLevel (level) == true)
{
// Send message for logging
// first send it to the debugger
Debugger.Log ((int) level, logswitch.strName, message);
// Send to the console device
if (m_fConsoleDeviceEnabled)
{
Console.Write(message);
}
}
}
/*
* Following are convenience entry points; all go through Log()
* Note that the (Switch switch, String message) variations
* are preferred.
*/
public static void Trace(LogSwitch logswitch, String message)
{
LogMessage (LoggingLevels.TraceLevel0, logswitch, message);
}
public static void Trace(String switchname, String message)
{
LogSwitch ls;
ls = LogSwitch.GetSwitch (switchname);
LogMessage (LoggingLevels.TraceLevel0, ls, message);
}
public static void Trace(String message)
{
LogMessage (LoggingLevels.TraceLevel0, GlobalSwitch, message);
}
public static void Status(LogSwitch logswitch, String message)
{
LogMessage (LoggingLevels.StatusLevel0, logswitch, message);
}
public static void Status(String switchname, String message)
{
LogSwitch ls;
ls = LogSwitch.GetSwitch (switchname);
LogMessage (LoggingLevels.StatusLevel0, ls, message);
}
public static void Status(String message)
{
LogMessage (LoggingLevels.StatusLevel0, GlobalSwitch, message);
}
public static void Warning(LogSwitch logswitch, String message)
{
LogMessage (LoggingLevels.WarningLevel, logswitch, message);
}
public static void Warning(String switchname, String message)
{
LogSwitch ls;
ls = LogSwitch.GetSwitch (switchname);
LogMessage (LoggingLevels.WarningLevel, ls, message);
}
public static void Warning(String message)
{
LogMessage (LoggingLevels.WarningLevel, GlobalSwitch, message);
}
public static void Error(LogSwitch logswitch, String message)
{
LogMessage (LoggingLevels.ErrorLevel, logswitch, message);
}
public static void Error(String switchname, String message)
{
LogSwitch ls;
ls = LogSwitch.GetSwitch (switchname);
LogMessage (LoggingLevels.ErrorLevel, ls, message);
}
public static void Error(String message)
{
LogMessage (LoggingLevels.ErrorLevel, GlobalSwitch, message);
}
public static void Panic(String message)
{
LogMessage (LoggingLevels.PanicLevel, GlobalSwitch, message);
}
// Native method to inform the EE about the creation of a new LogSwitch
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern void AddLogSwitch(LogSwitch logSwitch);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern void ModifyLogSwitch (int iNewLevel, String strSwitchName, String strParentName);
}
}
|