OLD | NEW |
| (Empty) |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 /// Instrument your code with counters, gauges, and more. | |
6 part of dart.developer; | |
7 | |
8 /// A UserTag can be used to group samples in the Observatory profiler. | |
9 abstract class UserTag { | |
10 /// The maximum number of UserTag instances that can be created by a program. | |
11 static const MAX_USER_TAGS = 64; | |
12 | |
13 factory UserTag(String label) => new _FakeUserTag(label); | |
14 | |
15 /// Label of [this]. | |
16 String get label; | |
17 | |
18 /// Make [this] the current tag for the isolate. Returns the current tag | |
19 /// before setting. | |
20 UserTag makeCurrent(); | |
21 | |
22 /// The default [UserTag] with label 'Default'. | |
23 static UserTag get defaultTag => _FakeUserTag._defaultTag; | |
24 } | |
25 | |
26 // This is a fake implementation of UserTag so that code can compile and run | |
27 // in dart2js. | |
28 class _FakeUserTag implements UserTag { | |
29 static Map _instances = {}; | |
30 | |
31 _FakeUserTag.real(this.label); | |
32 | |
33 factory _FakeUserTag(String label) { | |
34 // Canonicalize by name. | |
35 var existingTag = _instances[label]; | |
36 if (existingTag != null) { | |
37 return existingTag; | |
38 } | |
39 // Throw an exception if we've reached the maximum number of user tags. | |
40 if (_instances.length == UserTag.MAX_USER_TAGS) { | |
41 throw new UnsupportedError( | |
42 'UserTag instance limit (${UserTag.MAX_USER_TAGS}) reached.'); | |
43 } | |
44 // Create a new instance and add it to the instance map. | |
45 var instance = new _FakeUserTag.real(label); | |
46 _instances[label] = instance; | |
47 return instance; | |
48 } | |
49 | |
50 final String label; | |
51 | |
52 UserTag makeCurrent() { | |
53 var old = _currentTag; | |
54 _currentTag = this; | |
55 return old; | |
56 } | |
57 | |
58 static final UserTag _defaultTag = new _FakeUserTag('Default'); | |
59 } | |
60 | |
61 var _currentTag = _FakeUserTag._defaultTag; | |
62 | |
63 /// Returns the current [UserTag] for the isolate. | |
64 UserTag getCurrentTag() { | |
65 return _currentTag; | |
66 } | |
67 | |
68 /// Abstract [Metric] class. Metric names must be unique, are hierarchical, | |
69 /// and use periods as separators. For example, 'a.b.c'. Uniqueness is only | |
70 /// enforced when a Metric is registered. The name of a metric cannot contain | |
71 /// the slash ('/') character. | |
72 abstract class Metric { | |
73 /// [name] of this metric. | |
74 final String name; | |
75 /// [description] of this metric. | |
76 final String description; | |
77 | |
78 Metric(this.name, this.description) { | |
79 if ((name == 'vm') || name.contains('/')) { | |
80 throw new ArgumentError('Invalid Metric name.'); | |
81 } | |
82 | |
83 } | |
84 | |
85 Map _toJSON(); | |
86 } | |
87 | |
88 /// A measured value with a min and max. Initial value is min. Value will | |
89 /// be clamped to the interval [min, max]. | |
90 class Gauge extends Metric { | |
91 final double min; | |
92 final double max; | |
93 | |
94 double _value; | |
95 double get value => _value; | |
96 set value(double v) { | |
97 if (v < min) { | |
98 v = min; | |
99 } else if (v > max) { | |
100 v = max; | |
101 } | |
102 _value = v; | |
103 } | |
104 | |
105 Gauge(String name, String description, this.min, this.max) | |
106 : super(name, description) { | |
107 if (min is! double) { | |
108 throw new ArgumentError('min must be a double'); | |
109 } | |
110 if (max is! double) { | |
111 throw new ArgumentError('max must be a double'); | |
112 } | |
113 if (!(min < max)) { | |
114 throw new ArgumentError('min must be less than max'); | |
115 } | |
116 _value = min; | |
117 } | |
118 | |
119 Map _toJSON() { | |
120 var map = { | |
121 'type': 'Gauge', | |
122 'id': 'metrics/$name', | |
123 'name': name, | |
124 'description': description, | |
125 'value': value, | |
126 'min': min, | |
127 'max': max, | |
128 }; | |
129 return map; | |
130 } | |
131 } | |
132 | |
133 | |
134 /// A changing value. Initial value is 0.0. | |
135 class Counter extends Metric { | |
136 Counter(String name, String description) | |
137 : super(name, description); | |
138 | |
139 double _value = 0.0; | |
140 double get value => _value; | |
141 set value(double v) { | |
142 _value = v; | |
143 } | |
144 | |
145 Map _toJSON() { | |
146 var map = { | |
147 'type': 'Counter', | |
148 'id': 'metrics/$name', | |
149 'name': name, | |
150 'description': description, | |
151 'value': value, | |
152 }; | |
153 return map; | |
154 } | |
155 } | |
156 | |
157 class Metrics { | |
158 static final Map<String, Metric> _metrics = new Map<String, Metric>(); | |
159 | |
160 /// Register [Metric]s to make them visible to Observatory. | |
161 static void register(Metric metric) { | |
162 if (metric is! Metric) { | |
163 throw new ArgumentError('metric must be a Metric'); | |
164 } | |
165 if (_metrics[metric.name] != null) { | |
166 throw new ArgumentError('Registered metrics have unique names'); | |
167 } | |
168 _metrics[metric.name] = metric; | |
169 } | |
170 | |
171 /// Deregister [Metric]s to make them not visible to Observatory. | |
172 static void deregister(Metric metric) { | |
173 if (metric is! Metric) { | |
174 throw new ArgumentError('metric must be a Metric'); | |
175 } | |
176 _metrics.remove(metric.name); | |
177 } | |
178 | |
179 static String _printMetric(String id) { | |
180 var metric = _metrics[id]; | |
181 if (metric == null) { | |
182 return null; | |
183 } | |
184 return JSON.encode(metric._toJSON()); | |
185 } | |
186 | |
187 static String _printMetrics() { | |
188 var metrics = []; | |
189 for (var metric in _metrics.values) { | |
190 metrics.add(metric._toJSON()); | |
191 } | |
192 var map = { | |
193 'type': 'MetricList', | |
194 'metrics': metrics, | |
195 }; | |
196 return JSON.encode(map); | |
197 } | |
198 } | |
OLD | NEW |