├── lib ├── report_adapters │ ├── logfile_report_adapter.dart │ ├── console_report_adapter.dart │ └── http_report_adapter.dart └── logmaster.dart ├── .gitignore ├── README.md ├── test ├── http_report_adapter_test.dart └── logmaster_test.dart ├── pubspec.yaml ├── LICENSE └── pubspec.lock /lib/report_adapters/logfile_report_adapter.dart: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .packages 2 | .pub 3 | packages/ 4 | example/ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Logmaster 2 | ========= 3 | 4 | A logger intended to catch exceptions or simply report activity, 5 | then post it to a server or store locally fo further inspection. 6 | 7 | The idea is that catching errors and forming error messages is separate from 8 | actually reporting them. By loading report-adapters on demand, we can use this library 9 | both in the backend and in the frontend. 10 | -------------------------------------------------------------------------------- /lib/report_adapters/console_report_adapter.dart: -------------------------------------------------------------------------------- 1 | class ConsoleReportAdapter { 2 | 3 | var logmaster; 4 | int log_level = 1; 5 | 6 | post(r, level, [stack_trace=""]) { 7 | // Only print this message into the console if it's not an Error, 8 | // in which case logmaster would've already thrown it! 9 | if((r is String) || level < 3) 10 | print("${this.logmaster.log_level_as_string(level)}: $r"); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /test/http_report_adapter_test.dart: -------------------------------------------------------------------------------- 1 | import '../lib/report_adapters/http_report_adapter.dart'; 2 | import "package:test/test.dart"; 3 | import 'dart:html'; 4 | 5 | void main() { 6 | 7 | var adapter; 8 | 9 | setUp(() { 10 | adapter = new HttpReportAdapter("https://cors-test.appspot.com/test"); 11 | }); 12 | 13 | test("sends an ajax request and acknowledges a 200 response from the server", () { 14 | return adapter.post("message", 2).then((resp) { 15 | expect(resp.response, equals('{"status":"ok"}')); 16 | }); 17 | }); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: logmaster 2 | version: 0.1.1 3 | description: > 4 | A logger intended to catch exceptions or simply report activity, 5 | then post it to a server or store locally fo further inspection. 6 | 7 | The idea is that catching errors and forming error messages is separate from 8 | actually reporting them. By loading report-adapters on demand, we can use this library 9 | both in the backend and in the frontend. 10 | 11 | author: Roman Snitko 12 | homepage: https://github.com/snitko/dart-logmaster 13 | 14 | dependencies: 15 | dev_dependencies: 16 | test: '>=0.12.0' 17 | dependency_overrides: 18 | -------------------------------------------------------------------------------- /lib/report_adapters/http_report_adapter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:html'; 2 | 3 | class HttpReportAdapter { 4 | 5 | var logmaster; 6 | int log_level = 2; 7 | String url; 8 | 9 | HttpReportAdapter(this.url) {} 10 | 11 | post(r, level, [stack_trace=""]) { 12 | 13 | var data = { 14 | 'message' : r, 15 | 'log_level' : log_level.toString(), 16 | }; 17 | 18 | if(this.logmaster != null) 19 | data['log_level_string'] = this.logmaster.log_level_as_string(level); 20 | 21 | return makeAjaxRequest({ "error": "${data["message"]}\nStack trace:\n$stack_trace" }); 22 | 23 | } 24 | 25 | makeAjaxRequest(data) { 26 | return HttpRequest.postFormData(this.url, data); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /lib/logmaster.dart: -------------------------------------------------------------------------------- 1 | library logmaster; 2 | import 'dart:async'; 3 | 4 | class Logmaster { 5 | 6 | bool throw_exceptions = true; // if set to true, after reports have been sent, raises errors 7 | List report_adapters = []; 8 | 9 | static Map LOG_LEVELS = { 10 | 'DEBUG': 0, 11 | 'INFO' : 1, 12 | 'WARN' : 2, 13 | 'ERROR': 3, 14 | 'FATAL': 4 15 | }; 16 | 17 | Logmaster(this.report_adapters) { 18 | // Backreference to the object, which is going to be using those adapters. 19 | // Helps it with determining the LOG_LEVEL string version, for instance. 20 | this.report_adapters.forEach((ra) => ra.logmaster = this); 21 | } 22 | 23 | capture(message, { log_level: null, stack_trace: "" }) { 24 | 25 | if(log_level == null) 26 | if(message is String) 27 | log_level = LOG_LEVELS['INFO']; 28 | else 29 | log_level = LOG_LEVELS['ERROR']; 30 | 31 | report(message, log_level, stack_trace); 32 | 33 | if(!(message is String) && throw_exceptions) 34 | throw(message); 35 | 36 | } 37 | 38 | /** Uses report adapters to send log messages to various targets */ 39 | report(report, log_level, [stack_trace=""]) { 40 | 41 | report_adapters.forEach((ra) { 42 | if(ra.log_level <= log_level) 43 | ra.post(report, log_level, stack_trace); 44 | }); 45 | 46 | } 47 | 48 | log_level_as_string(int level) { 49 | for(var k in LOG_LEVELS.keys) { 50 | if(LOG_LEVELS[k] == level) 51 | return k; 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /test/logmaster_test.dart: -------------------------------------------------------------------------------- 1 | import '../lib/logmaster.dart'; 2 | import '../lib/report_adapters/console_report_adapter.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | var reports = []; 6 | 7 | class ReportAdapter1 { 8 | var logmaster; 9 | var log_level = 1; 10 | post(r, level, [stack_trace=""]) => reports.add("report for log level $level added to ReportAdapter1"); 11 | } 12 | 13 | class ReportAdapter2 { 14 | var logmaster; 15 | var log_level = 2; 16 | post(r, level, [stack_trace=""]) => reports.add("report for log level $level added to ReportAdapter2"); 17 | } 18 | 19 | void main() { 20 | 21 | var logmaster; 22 | 23 | setUp(() { 24 | reports = []; 25 | var report_adapters = [new ReportAdapter1(), new ReportAdapter2(), new ConsoleReportAdapter()]; 26 | logmaster = new Logmaster(report_adapters); 27 | }); 28 | 29 | test("raises error if exception is passed", () { 30 | expect(() => logmaster.capture(new Exception("hello world")), throws); 31 | expect(() => logmaster.capture("Just a message"), returnsNormally); 32 | }); 33 | 34 | test("reports error to all of the adapters with the log levels above or equal to the reported one", () { 35 | logmaster.capture("info message", log_level: 1); 36 | logmaster.capture("warn message", log_level: 2); 37 | expect(reports, equals([ 38 | "report for log level 1 added to ReportAdapter1", 39 | "report for log level 2 added to ReportAdapter1", 40 | "report for log level 2 added to ReportAdapter2" 41 | ])); 42 | }); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See http://pub.dartlang.org/doc/glossary.html#lockfile 3 | packages: 4 | analyzer: 5 | description: 6 | name: analyzer 7 | url: "https://pub.dartlang.org" 8 | source: hosted 9 | version: "0.27.2" 10 | args: 11 | description: 12 | name: args 13 | url: "https://pub.dartlang.org" 14 | source: hosted 15 | version: "0.13.4" 16 | async: 17 | description: 18 | name: async 19 | url: "https://pub.dartlang.org" 20 | source: hosted 21 | version: "1.10.0" 22 | barback: 23 | description: 24 | name: barback 25 | url: "https://pub.dartlang.org" 26 | source: hosted 27 | version: "0.15.2+7" 28 | boolean_selector: 29 | description: 30 | name: boolean_selector 31 | url: "https://pub.dartlang.org" 32 | source: hosted 33 | version: "1.0.1" 34 | charcode: 35 | description: 36 | name: charcode 37 | url: "https://pub.dartlang.org" 38 | source: hosted 39 | version: "1.1.0" 40 | collection: 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.9.1" 46 | convert: 47 | description: 48 | name: convert 49 | url: "https://pub.dartlang.org" 50 | source: hosted 51 | version: "1.1.0" 52 | crypto: 53 | description: 54 | name: crypto 55 | url: "https://pub.dartlang.org" 56 | source: hosted 57 | version: "1.0.0" 58 | csslib: 59 | description: 60 | name: csslib 61 | url: "https://pub.dartlang.org" 62 | source: hosted 63 | version: "0.13.1" 64 | glob: 65 | description: 66 | name: glob 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "1.1.2" 70 | html: 71 | description: 72 | name: html 73 | url: "https://pub.dartlang.org" 74 | source: hosted 75 | version: "0.12.2+2" 76 | http: 77 | description: 78 | name: http 79 | url: "https://pub.dartlang.org" 80 | source: hosted 81 | version: "0.11.3+9" 82 | http_multi_server: 83 | description: 84 | name: http_multi_server 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "2.0.1" 88 | http_parser: 89 | description: 90 | name: http_parser 91 | url: "https://pub.dartlang.org" 92 | source: hosted 93 | version: "2.2.1" 94 | logging: 95 | description: 96 | name: logging 97 | url: "https://pub.dartlang.org" 98 | source: hosted 99 | version: "0.11.3" 100 | matcher: 101 | description: 102 | name: matcher 103 | url: "https://pub.dartlang.org" 104 | source: hosted 105 | version: "0.12.0+2" 106 | mime: 107 | description: 108 | name: mime 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "0.9.3" 112 | package_config: 113 | description: 114 | name: package_config 115 | url: "https://pub.dartlang.org" 116 | source: hosted 117 | version: "0.1.3" 118 | package_resolver: 119 | description: 120 | name: package_resolver 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.0.2" 124 | path: 125 | description: 126 | name: path 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "1.3.9" 130 | plugin: 131 | description: 132 | name: plugin 133 | url: "https://pub.dartlang.org" 134 | source: hosted 135 | version: "0.1.0" 136 | pool: 137 | description: 138 | name: pool 139 | url: "https://pub.dartlang.org" 140 | source: hosted 141 | version: "1.2.3" 142 | pub_semver: 143 | description: 144 | name: pub_semver 145 | url: "https://pub.dartlang.org" 146 | source: hosted 147 | version: "1.2.4" 148 | shelf: 149 | description: 150 | name: shelf 151 | url: "https://pub.dartlang.org" 152 | source: hosted 153 | version: "0.6.5" 154 | shelf_packages_handler: 155 | description: 156 | name: shelf_packages_handler 157 | url: "https://pub.dartlang.org" 158 | source: hosted 159 | version: "1.0.0" 160 | shelf_static: 161 | description: 162 | name: shelf_static 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "0.2.3+3" 166 | shelf_web_socket: 167 | description: 168 | name: shelf_web_socket 169 | url: "https://pub.dartlang.org" 170 | source: hosted 171 | version: "0.2.0" 172 | source_map_stack_trace: 173 | description: 174 | name: source_map_stack_trace 175 | url: "https://pub.dartlang.org" 176 | source: hosted 177 | version: "1.1.4" 178 | source_maps: 179 | description: 180 | name: source_maps 181 | url: "https://pub.dartlang.org" 182 | source: hosted 183 | version: "0.10.2" 184 | source_span: 185 | description: 186 | name: source_span 187 | url: "https://pub.dartlang.org" 188 | source: hosted 189 | version: "1.2.2" 190 | stack_trace: 191 | description: 192 | name: stack_trace 193 | url: "https://pub.dartlang.org" 194 | source: hosted 195 | version: "1.6.5" 196 | stream_channel: 197 | description: 198 | name: stream_channel 199 | url: "https://pub.dartlang.org" 200 | source: hosted 201 | version: "1.3.1" 202 | string_scanner: 203 | description: 204 | name: string_scanner 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "0.1.4+1" 208 | test: 209 | description: 210 | name: test 211 | url: "https://pub.dartlang.org" 212 | source: hosted 213 | version: "0.12.17+3" 214 | typed_data: 215 | description: 216 | name: typed_data 217 | url: "https://pub.dartlang.org" 218 | source: hosted 219 | version: "1.1.2" 220 | utf: 221 | description: 222 | name: utf 223 | url: "https://pub.dartlang.org" 224 | source: hosted 225 | version: "0.9.0+3" 226 | watcher: 227 | description: 228 | name: watcher 229 | url: "https://pub.dartlang.org" 230 | source: hosted 231 | version: "0.9.7" 232 | web_socket_channel: 233 | description: 234 | name: web_socket_channel 235 | url: "https://pub.dartlang.org" 236 | source: hosted 237 | version: "1.0.2" 238 | yaml: 239 | description: 240 | name: yaml 241 | url: "https://pub.dartlang.org" 242 | source: hosted 243 | version: "2.1.8" 244 | sdks: 245 | dart: ">=1.14.0 <2.0.0" 246 | --------------------------------------------------------------------------------