//////////////////////////////////////////////////////////////////////////////// // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You 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. // //////////////////////////////////////////////////////////////////////////////// package mx.logging { import mx.logging.errors.InvalidCategoryError; import mx.managers.ISystemManager; import mx.managers.SystemManager; import mx.resources.IResourceManager; import mx.resources.ResourceManager; [ResourceBundle("logging")] /** * Provides pseudo-hierarchical logging capabilities with multiple format and * output options. * The log system consists of two major components, the logger and a target. * You can use the logger to send information to a target. * The target is responsible for formatting and general output of the log data. *
* Loggers are singleton instances created for a particular category of * information. * Typically, the category is the package name of the component * that desires to log information. * The category provides users the ability to specify what log information they * are interested in. * Multiple categories can be selected and combined with regular expressions. * This allows for both broad and narrow logging information to be acquired. * For example, you might be interested in all logging information under * the "mx.messaging" and "mx.rpc" packages and want the output from these * packages to be formatted as XML. * To get the all of the logging information under the "mx.messaging" category * including sub-packages and components a wildcard expression is required, such as * "mx.messaging.~~". * See the code example below for more details. *
*Targets provide the output mechanism of the data being logged.
* This mechanism typically includes formatting, transmission, or storage, but
* can be anything possible under the VM.
* There are two targets provided: MiniDebugTarget
and
* TraceTarget
.
* Each of these writers take the current log information and "sends" it
* somewhere for display and/or storage.
* Targets also provide the specification of what log data to output.
*
* ... * import mx.logging.targets.*; * import mx.logging.*; * * private function initLogging():void { * // Create a target. * var logTarget:TraceTarget = new TraceTarget(); * * // Log only messages for the classes in the mx.rpc.* and * // mx.messaging packages. * logTarget.filters=["mx.rpc.*","mx.messaging.*"]; * * // Log all log levels. * logTarget.level = LogEventLevel.ALL; * * // Add date, time, category, and log level to the output. * logTarget.includeDate = true; * logTarget.includeTime = true; * logTarget.includeCategory = true; * logTarget.includeLevel = true; * * // Begin logging. * Log.addTarget(logTarget); * } * ... ** * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public class Log { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Class variables // //-------------------------------------------------------------------------- /** * @private * Sentinal value for the target log level to indicate no logging. */ private static var NONE:int = int.MAX_VALUE; /** * @private * The most verbose supported log level among registered targets. */ private static var _targetLevel:int = NONE; // Initialize target level to a value out of range. /** * @private * An associative Array of existing loggers keyed by category */ private static var _loggers:Array; /** * @private * Array of targets that should be searched any time * a new logger is created. */ private static var _targets:Array = []; /** * @private * Storage for the resourceManager getter. * This gets initialized on first access, * not at static initialization time, in order to ensure * that the Singleton registry has already been initialized. */ private static var _resourceManager:IResourceManager; /** * @private * A reference to the object which manages * all of the application's localized resources. * This is a singleton instance which implements * the IResourceManager interface. */ private static function get resourceManager():IResourceManager { if (!_resourceManager) _resourceManager = ResourceManager.getInstance(); return _resourceManager; } //-------------------------------------------------------------------------- // // Class methods // //-------------------------------------------------------------------------- /** * Indicates whether a fatal level log event will be processed by a * log target. * * @return true if a fatal level log event will be logged; otherwise false. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function isFatal():Boolean { return (_targetLevel <= LogEventLevel.FATAL) ? true : false; } /** * Indicates whether an error level log event will be processed by a * log target. * * @return true if an error level log event will be logged; otherwise false. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function isError():Boolean { return (_targetLevel <= LogEventLevel.ERROR) ? true : false; } /** * Indicates whether a warn level log event will be processed by a * log target. * * @return true if a warn level log event will be logged; otherwise false. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function isWarn():Boolean { return (_targetLevel <= LogEventLevel.WARN) ? true : false; } /** * Indicates whether an info level log event will be processed by a * log target. * * @return true if an info level log event will be logged; otherwise false. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function isInfo():Boolean { return (_targetLevel <= LogEventLevel.INFO) ? true : false; } /** * Indicates whether a debug level log event will be processed by a * log target. * * @return true if a debug level log event will be logged; otherwise false. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function isDebug():Boolean { return (_targetLevel <= LogEventLevel.DEBUG) ? true : false; } /** * Allows the specified target to begin receiving notification of log * events. * * @param The specific target that should capture log events. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function addTarget(target:ILoggingTarget):void { if (target) { var filters:Array = target.filters; var logger:ILogger; // need to find what filters this target matches and set the specified // target as a listener for that logger. for (var i:String in _loggers) { if (categoryMatchInFilterList(i, filters)) target.addLogger(ILogger(_loggers[i])); } // if we found a match all is good, otherwise we need to // put the target in a waiting queue in the event that a logger // is created that this target cares about. _targets.push(target); if (_targetLevel == NONE) _targetLevel = target.level else if (target.level < _targetLevel) _targetLevel = target.level; } else { var message:String = resourceManager.getString( "logging", "invalidTarget"); throw new ArgumentError(message); } } /** * Stops the specified target from receiving notification of log * events. * * @param The specific target that should capture log events. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function removeTarget(target:ILoggingTarget):void { if (target) { var filters:Array = target.filters; var logger:ILogger; // Disconnect this target from any matching loggers. for (var i:String in _loggers) { if (categoryMatchInFilterList(i, filters)) { target.removeLogger(ILogger(_loggers[i])); } } // Remove the target. for (var j:int = 0; j<_targets.length; j++) { if (target == _targets[j]) { _targets.splice(j, 1); j--; } } resetTargetLevel(); } else { var message:String = resourceManager.getString( "logging", "invalidTarget"); throw new ArgumentError(message); } } /** * Returns the logger associated with the specified category. * If the category given doesn't exist a new instance of a logger will be * returned and associated with that category. * Categories must be at least one character in length and may not contain * any blanks or any of the following characters: * []~$^&\/(){}<>+=`!#%?,:;'"@ * This method will throw an
InvalidCategoryError
if the
* category specified is malformed.
*
* @param category The category of the logger that should be returned.
*
* @return An instance of a logger object for the specified name.
* If the name doesn't exist, a new instance with the specified
* name is returned.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public static function getLogger(category:String):ILogger
{
checkCategory(category);
if (!_loggers)
_loggers = [];
// get the logger for the specified category or create one if it
// doesn't exist
var result:ILogger = _loggers[category];
if (result == null)
{
result = new LogLogger(category);
_loggers[category] = result;
}
// check to see if there are any targets waiting for this logger.
var target:ILoggingTarget;
for (var i:int = 0; i < _targets.length; i++)
{
target = ILoggingTarget(_targets[i]);
if (categoryMatchInFilterList(category, target.filters))
target.addLogger(result);
}
return result;
}
/**
* This method removes all of the current loggers from the cache.
* Subsquent calls to the getLogger()
method return new instances
* of loggers rather than any previous instances with the same category.
* This method is intended for use in debugging only.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public static function flush():void
{
_loggers = [];
_targets = [];
_targetLevel = NONE;
}
/**
* This method checks the specified string value for illegal characters.
*
* @param value The String to check for illegal characters.
* The following characters are not valid:
* []~$^&\/(){}<>+=`!#%?,:;'"@
* @return true
if there are any illegal characters found,
* false
otherwise
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public static function hasIllegalCharacters(value:String):Boolean
{
return value.search(/[\[\]\~\$\^\&\\(\)\{\}\+\?\/=`!@#%,:;'"<>\s]/) != -1;
}
// private members
/**
* This method checks that the specified category matches any of the filter
* expressions provided in the filters
Array.
*
* @param category The category to match against
* @param filters A list of Strings to check category against.
* @return true
if the specified category matches any of the
* filter expressions found in the filters list, false
* otherwise.
* @private
*/
private static function categoryMatchInFilterList(category:String, filters:Array):Boolean
{
var result:Boolean = false;
var filter:String;
var index:int = -1;
for (var i:uint = 0; i < filters.length; i++)
{
filter = filters[i];
// first check to see if we need to do a partial match
// do we have an asterisk?
index = filter.indexOf("*");
if (index == 0)
return true;
index = index < 0 ? index = category.length : index -1;
if (category.substring(0, index) == filter.substring(0, index))
return true;
}
return false;
}
/**
* This method will ensure that a valid category string has been specified.
* If the category is not valid an InvalidCategoryError
will
* be thrown.
* Categories can not contain any blanks or any of the following characters:
* []`*~,!#$%^&()]{}+=\|'";?><./@ or be less than 1 character in length.
* @private
*/
private static function checkCategory(category:String):void
{
var message:String;
if (category == null || category.length == 0)
{
message = resourceManager.getString(
"logging", "invalidLen");
throw new InvalidCategoryError(message);
}
if (hasIllegalCharacters(category) || (category.indexOf("*") != -1))
{
message = resourceManager.getString(
"logging", "invalidChars");
throw new InvalidCategoryError(message);
}
}
/**
* @private
* This method resets the Log's target level to the most verbose log level
* for the currently registered targets.
*/
private static function resetTargetLevel():void
{
var minLevel:int = NONE;
for (var i:int = 0; i < _targets.length; i++)
{
if (minLevel == NONE || _targets[i].level < minLevel)
minLevel = _targets[i].level;
}
_targetLevel = minLevel;
}
}
}