| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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. |
| * <p> |
| * 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. |
| * </p> |
| * <p>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: <code>MiniDebugTarget</code> and |
| * <code>TraceTarget</code>. |
| * 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. |
| * </p> |
| * |
| * @example |
| * <pre> |
| * ... |
| * 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); |
| * } |
| * ... |
| * </pre> |
| * |
| * @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 <code>InvalidCategoryError</code> 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 <code>getLogger()</code> 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 <code>true</code> if there are any illegal characters found, |
| * <code>false</code> 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 <code>filters</code> Array. |
| * |
| * @param category The category to match against |
| * @param filters A list of Strings to check category against. |
| * @return <code>true</code> if the specified category matches any of the |
| * filter expressions found in the filters list, <code>false</code> |
| * 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 <code>InvalidCategoryError</code> 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; |
| } |
| } |
| |
| } |