| 1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | import 'dart:core'; |
| 6 | import 'dart:io'; |
| 7 | |
| 8 | /// Determines the level of logging. |
| 9 | /// |
| 10 | /// Verbosity is increasing from one (none) to five (fine). The sixth level |
| 11 | /// (all) logs everything. |
| 12 | enum LoggingLevel { |
| 13 | /// Logs no logs. |
| 14 | none, |
| 15 | |
| 16 | /// Logs severe messages at the most (severe messages are always logged). |
| 17 | /// |
| 18 | /// Severe means that the process has encountered a critical level of failure |
| 19 | /// in which it cannot recover and will terminate as a result. |
| 20 | severe, |
| 21 | |
| 22 | /// Logs warning messages at the most. |
| 23 | /// |
| 24 | /// Warning implies that an error was encountered, but the process will |
| 25 | /// attempt to continue, and may/may not succeed. |
| 26 | warning, |
| 27 | |
| 28 | /// Logs info messages at the most. |
| 29 | /// |
| 30 | /// An info message is for determining information about the state of the |
| 31 | /// application as it runs through execution. |
| 32 | info, |
| 33 | |
| 34 | /// Logs fine logs at the most. |
| 35 | /// |
| 36 | /// A fine message is one that is not important for logging outside of |
| 37 | /// debugging potential issues in the application. |
| 38 | fine, |
| 39 | |
| 40 | /// Logs everything. |
| 41 | all, |
| 42 | } |
| 43 | |
| 44 | /// Signature of a function that logs a [LogMessage]. |
| 45 | typedef LoggingFunction = void Function(LogMessage log); |
| 46 | |
| 47 | /// The default logging function. |
| 48 | /// |
| 49 | /// Runs the [print] function using the format string: |
| 50 | /// '[${log.levelName}]::${log.tag}--${log.time}: ${log.message}' |
| 51 | /// |
| 52 | /// Exits with status code 1 if the `log` is [LoggingLevel.severe]. |
| 53 | void defaultLoggingFunction(LogMessage log) { |
| 54 | // ignore: avoid_print |
| 55 | print('[ ${log.levelName}]:: ${log.tag}-- ${log.time}: ${log.message}' ); |
| 56 | if (log.level == LoggingLevel.severe) { |
| 57 | exit(1); |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | /// Represents a logging message created by the logger. |
| 62 | /// |
| 63 | /// Includes a message, the time the message was created, the level of the log |
| 64 | /// as an enum, the name of the level as a string, and a tag. This class is used |
| 65 | /// to print from the global logging function defined in |
| 66 | /// [Logger.loggingFunction] (a function that can be user-defined). |
| 67 | class LogMessage { |
| 68 | /// Creates a log, including the level of the log, the time it was created, |
| 69 | /// and the actual log message. |
| 70 | /// |
| 71 | /// When this message is created, it sets its [time] to [DateTime.now]. |
| 72 | LogMessage(this.message, this.tag, this.level) |
| 73 | : levelName = level.toString().substring(level.toString().indexOf('.' ) + 1), |
| 74 | time = DateTime.now(); |
| 75 | |
| 76 | /// The actual log message. |
| 77 | final String message; |
| 78 | |
| 79 | /// The time the log message was created. |
| 80 | final DateTime time; |
| 81 | |
| 82 | /// The level of this log. |
| 83 | final LoggingLevel level; |
| 84 | |
| 85 | /// The human readable level of this log. |
| 86 | final String levelName; |
| 87 | |
| 88 | /// The tag associated with the message. This is set to [Logger.tag] when |
| 89 | /// emitted by a [Logger] object. |
| 90 | final String tag; |
| 91 | } |
| 92 | |
| 93 | /// Logs messages using the global [LoggingFunction] and logging level. |
| 94 | /// |
| 95 | /// Example of setting log level to [LoggingLevel.warning] and creating a |
| 96 | /// logging function: |
| 97 | /// |
| 98 | /// ```dart |
| 99 | /// Logger.globalLevel = LoggingLevel.warning; |
| 100 | /// ``` |
| 101 | class Logger { |
| 102 | /// Creates a logger with the given [tag]. |
| 103 | Logger(this.tag); |
| 104 | |
| 105 | /// The tag associated with the log message (usable in the logging function). |
| 106 | /// [LogMessage] objects emitted by this class will have [LogMessage.tag] set |
| 107 | /// to this value. |
| 108 | final String tag; |
| 109 | |
| 110 | /// Determines what to do when the [Logger] creates and attempts to log a |
| 111 | /// [LogMessage] object. |
| 112 | /// |
| 113 | /// This function can be reassigned to whatever functionality of your |
| 114 | /// choosing, so long as it has the same signature of [LoggingFunction] (it |
| 115 | /// can also be an asynchronous function, if doing file I/O, for |
| 116 | /// example). |
| 117 | static LoggingFunction loggingFunction = defaultLoggingFunction; |
| 118 | |
| 119 | /// Determines the logging level all [Logger] instances use. |
| 120 | static LoggingLevel globalLevel = LoggingLevel.none; |
| 121 | |
| 122 | /// Logs a [LoggingLevel.severe] level `message`. |
| 123 | /// |
| 124 | /// Severe messages are always logged, regardless of what level is set. |
| 125 | void severe(String message) { |
| 126 | loggingFunction(LogMessage(message, tag, LoggingLevel.severe)); |
| 127 | } |
| 128 | |
| 129 | /// Logs a [LoggingLevel.warning] level `message`. |
| 130 | void warning(String message) { |
| 131 | if (globalLevel.index >= LoggingLevel.warning.index) { |
| 132 | loggingFunction(LogMessage(message, tag, LoggingLevel.warning)); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | /// Logs a [LoggingLevel.info] level `message`. |
| 137 | void info(String message) { |
| 138 | if (globalLevel.index >= LoggingLevel.info.index) { |
| 139 | loggingFunction(LogMessage(message, tag, LoggingLevel.info)); |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | /// Logs a [LoggingLevel.fine] level `message`. |
| 144 | void fine(String message) { |
| 145 | if (globalLevel.index >= LoggingLevel.fine.index) { |
| 146 | loggingFunction(LogMessage(message, tag, LoggingLevel.fine)); |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | |