diff --git a/changelog.md b/changelog.md index 0009277..119692a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,9 @@ # Changelog +## 0.0.4 + +- Moved `sanitizeStacktrace` into the main library + ## 0.0.3 - Replaced optional positional arguments with named arguments @@ -9,7 +13,7 @@ ## 0.0.2 - Fixed a bug in `analytics.sendTiming()` - + ## 0.0.1 - Initial version, created by Stagehand diff --git a/lib/src/usage_impl.dart b/lib/src/usage_impl.dart index 7a24819..6ee4e43 100644 --- a/lib/src/usage_impl.dart +++ b/lib/src/usage_impl.dart @@ -13,9 +13,6 @@ import '../usage.dart'; final int _MAX_EXCEPTION_LENGTH = 100; -// Matches file:/, non-ws, /, non-ws, .dart -final RegExp _pathRegex = new RegExp(r'file:/\S+/(\S+\.dart)'); - String postEncode(Map map) { // &foo=bar return map.keys.map((key) { @@ -24,30 +21,6 @@ String postEncode(Map map) { }).join('&'); } -/** - * Santitize a string potentially containing file paths. This will remove all - * but the last file name in order to remove any PII that may be contained in - * the full file path. For example, this will shorten: - * - * file:///Users/foobar/tmp/error.dart - * - * to - * - * error.dart - */ -String sanitizeFilePaths(String stackTrace) { - Iterable iter = _pathRegex.allMatches(stackTrace); - iter = iter.toList().reversed; - - for (Match match in iter) { - String replacement = match.group(1); - stackTrace = stackTrace.substring(0, match.start) - + replacement + stackTrace.substring(match.end); - } - - return stackTrace; -} - /** * A throttling algorithim. This models the throttling after a bucket with * water dripping into it at the rate of 1 drop per second. If the bucket has diff --git a/lib/usage.dart b/lib/usage.dart index 9ddcb9e..9496095 100644 --- a/lib/usage.dart +++ b/lib/usage.dart @@ -26,6 +26,9 @@ library usage; import 'dart:async'; +// Matches file:/, non-ws, /, non-ws, .dart +final RegExp _pathRegex = new RegExp(r'file:/\S+/(\S+\.dart)'); + /** * An interface to a Google Analytics session. [AnalyticsHtml] and [AnalyticsIO] * are concrete implementations of this interface. [AnalyticsMock] can be used @@ -144,3 +147,36 @@ class AnalyticsMock extends Analytics { return new Future.value(); } } + +/** + * Santitize a stacktrace. This will shorten file paths in order to remove any + * PII that may be contained in the full file path. For example, this will + * shorten `file:///Users/foobar/tmp/error.dart` to `error.dart`. + * + * If [shorten] is `true`, this method will also attempt to compress the text + * of the stacktrace. GA has a 100 char limit on the text that can be sent for + * an exception. This will try and make those first 100 chars contain + * information useful to debugging the issue. + */ +String sanitizeStacktrace(dynamic st, {bool shorten: true}) { + String str = '${st}'; + + Iterable iter = _pathRegex.allMatches(str); + iter = iter.toList().reversed; + + for (Match match in iter) { + String replacement = match.group(1); + str = str.substring(0, match.start) + + replacement + str.substring(match.end); + } + + if (shorten) { + // Shorten the stacktrace up a bit. + str = str + .replaceAll('(package:', '(') + .replaceAll('(dart:', '(') + .replaceAll(new RegExp(r'\s+'), ' '); + } + + return str; +} diff --git a/pubspec.yaml b/pubspec.yaml index 6ab1556..21e61f2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ # BSD-style license that can be found in the LICENSE file. name: usage -version: 0.0.4-dev +version: 0.0.4 description: A Google Analytics wrapper for both command-line and web apps. homepage: https://github.com/dart-lang/usage author: Dart Team diff --git a/readme.md b/readme.md index 496ff0b..520c4b9 100644 --- a/readme.md +++ b/readme.md @@ -3,7 +3,7 @@ `usage` is a wrapper around Google Analytics for both command-line apps and web apps. -[![Build Status](https://travis-ci.org/dart-lang/usage.svg)](https://travis-ci.org/dart-lang/usage) +[![Build Status](https://travis-ci.org/dart-lang/usage.svg)](https://travis-ci.org/dart-lang/usage) [![Coverage Status](https://img.shields.io/coveralls/dart-lang/usage.svg)](https://coveralls.io/r/dart-lang/usage?branch=master) ## For web apps diff --git a/test/usage_impl_test.dart b/test/usage_impl_test.dart index 80b8690..6622825 100644 --- a/test/usage_impl_test.dart +++ b/test/usage_impl_test.dart @@ -54,21 +54,6 @@ void defineTests() { }); }); - group('sanitizeFilePaths', () { - test('replace file', () { - expect(sanitizeFilePaths( - '(file:///Users/foo/tmp/error.dart:3:13)'), - '(error.dart:3:13)'); - }); - - test('replace files', () { - expect(sanitizeFilePaths( - 'foo (file:///Users/foo/tmp/error.dart:3:13)\n' - 'bar (file:///Users/foo/tmp/error.dart:3:13)'), - 'foo (error.dart:3:13)\nbar (error.dart:3:13)'); - }); - }); - group('postEncode', () { test('simple', () { Map map = {'foo': 'bar', 'baz': 'qux norf'}; diff --git a/test/usage_test.dart b/test/usage_test.dart index 5edfa45..e92caf3 100644 --- a/test/usage_test.dart +++ b/test/usage_test.dart @@ -19,4 +19,41 @@ void defineTests() { mock.setSessionValue('val', 'ue'); }); }); + + group('sanitizeStacktrace', () { + test('replace file', () { + expect(sanitizeStacktrace( + '(file:///Users/foo/tmp/error.dart:3:13)', + shorten: false), + '(error.dart:3:13)'); + }); + + test('replace files', () { + expect(sanitizeStacktrace( + 'foo (file:///Users/foo/tmp/error.dart:3:13)\n' + 'bar (file:///Users/foo/tmp/error.dart:3:13)', + shorten: false), + 'foo (error.dart:3:13)\nbar (error.dart:3:13)'); + }); + + test('shorten 1', () { + expect(sanitizeStacktrace( + '(file:///Users/foo/tmp/error.dart:3:13)'), + '(error.dart:3:13)'); + }); + + test('shorten 2', () { + expect(sanitizeStacktrace( + 'foo (file:///Users/foo/tmp/error.dart:3:13)\n' + 'bar (file:///Users/foo/tmp/error.dart:3:13)'), + 'foo (error.dart:3:13) bar (error.dart:3:13)'); + }); + + test('shorten 3', () { + expect(sanitizeStacktrace( + 'foo (package:foo/foo.dart:3:13)\n' + 'bar (dart:async/schedule_microtask.dart:41)'), + 'foo (foo/foo.dart:3:13) bar (async/schedule_microtask.dart:41)'); + }); + }); }