You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/MetricGroup.md
+45-19Lines changed: 45 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,20 +1,32 @@
1
1
# MetricGroup
2
2
3
-
Because one of the goals of BosunReporter.NET is to encourage using tags to differentiate subsets of the same data (instead of separate metric names), metric groups are built into the library. A metric group is a collection of metrics with the same name, but with different tag values. For example, let's say we have a counter which counts every request. We might want to tag this counter to indicate how many requests were successful versus how many encountered an error. Start by creating a class for our counter, as usual.
3
+
Because one of the goals of BosunReporter.NET is to encourage using tags to differentiate subsets of the same data (instead of separate metric names), metric groups are built into the library. A metric group is a collection of metrics with the same name, but with different tag values. For example, let's say we have a counter which counts every request. We might want to tag this counter to indicate how many requests were successful versus how many encountered an error.
4
+
5
+
Let's start by defining an enum of the result types we want to track.
Now, instead of manually creating a metric for each of the result values we want ("success", "error", etc), we can simply create a group which will enable us to create those metrics implicitly.
26
+
Now, instead of manually creating a metric for each of the result values we want (Success and Error), we can simply create a group which will enable us to create those metrics implicitly.
"A count of the number of requests", // description
@@ -23,21 +35,18 @@ var requestCounter = collector.GetMetricGroup<string, RequestCounter>(
23
35
// MetricGroup.Add() creates a metric if it does not already exist, and returns that metric.
24
36
// Best-practice is to call Add() as close to application-startup as possible to avoid
25
37
// "Unknown" Bosun alerts.
26
-
requestCounter.Add("success");
27
-
requestCounter.Add("error");
28
-
29
-
...
38
+
requestCounter.Add(Result.Success);
39
+
requestCounter.Add(Result.Error);
30
40
31
-
// as long as Add() has been previously called for each tag value, you can use indexer syntax
32
-
if (error==null)
33
-
requestCounter["success"].Increment();
34
-
else
35
-
requestCounter["error"].Increment();
41
+
// once they've been added, we can use indexer syntax to access those metrics. For example...
42
+
requestCounter[Result.Success].Increment();
36
43
```
37
44
38
-
Note that we used the generic type arguments `<string, RequestCounter>` in the example above. This determines the signature of the factory, which is `Func<string, RequestCounter>` in this example because it takes a single string argument, and returns a `RequestCounter`. It also determines the method signature of `Add()`.
45
+
Note that we used the generic type arguments `<Result, RequestCounter>` in the example above. This determines the signature of the factory, which is `Func<Result, RequestCounter>` in this example because it takes a single `Result` argument, and returns a `RequestCounter`. It also determines the method signature of `Add()`.
39
46
40
-
> Because `RequestCounter` has a constructor which matches the type signature provided (accepts a single string, and returns an instance of RequestCounter), we could have omitted the factory argument. The metric group will use that constructor to generate a default factory.
47
+
> Because `RequestCounter` has a constructor which matches the type signature provided (accepts a single Result, and returns an instance of RequestCounter), we could have omitted the factory argument. The metric group will use that constructor to generate a default factory.
48
+
49
+
## Multiple Tags
41
50
42
51
You can also create metric groups which is differentiated by more than one tag (MetricGroup currently supports up to 5, though splitting on more than 2 or 3 may be a code-smell). Simply add additional type arguments to the MetricGroup generic type constructor. Let's use a three-tag counter as an example:
43
52
@@ -46,13 +55,13 @@ public ThreeTagCounter : Counter
> Value types or strings are always best for the metric group arguments. Objects are okay as long as they play well as dictionary keys or values inside a Tuple which is used as a dictionary key. This generally means any object used as a metric group argument should implement IEquatable<T> and have a good GetHashCode implementation.
97
+
> Value types or strings are always best for the metric group arguments. Objects are okay as long as they play well as dictionary keys or values inside a Tuple which is used as a dictionary key. This generally means any object used as a metric group argument should implement IEquatable<T> and have a good GetHashCode implementation.
98
+
99
+
## Auto-Populate from Enum Values
100
+
101
+
In the first example, we populated all of the values of our `Result` enum into the group using:
102
+
103
+
```csharp
104
+
requestCounter.Add(Result.Success);
105
+
requestCounter.Add(Result.Error);
106
+
```
107
+
108
+
Since it's very common to want one metric per enum value, there is a helper method which does just that. The code below is functionally equivalent to the code above.
109
+
110
+
```csharp
111
+
requestCounter.PopulateFromEnum();
112
+
```
113
+
114
+
However, this helper method is only available when there is only one input type parameter, and that type parameter is an enum type. For example, you could use `PopulateFromEnum` on a group with the type signature `MetricGroup<SomeEnum, SomeMetric>`, but not on `MetricGroup<SomeEnum, int, SomeMetric>` because it has more than one input type parameter (`SomeEnum` and `int`).
@@ -36,7 +36,7 @@ Gauges describe a measurement at a point in time. A good example would be measur
36
36
These are great for metrics where you want to record snapshots of a value, like CPU or memory usage. Pretend we have a method called `GetMemoryUsage` which returns a double. Now, let's write a snapshot gauge which calls that automatically at every metrics reporting interval.
That's it. There's no reason to even assign the gauge to a variable.
@@ -48,7 +48,7 @@ That's it. There's no reason to even assign the gauge to a variable.
48
48
These are ideal for low-volume event-based data where it's practical to send all of the data points to Bosun. If you have a measurable event which occurs once every few seconds, then, instead of aggregating, you may want to use an event gauge. Every time you call `.Record()` on an event gauge, the metric will be serialized and queued. The queued metrics will be sent to Bosun on the normal reporting interval, like all other metrics.
Copy file name to clipboardExpand all lines: docs/Tags.md
+8-8Lines changed: 8 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,24 +25,24 @@ public class RouteCounter : Counter
25
25
And then let's instantiate one.
26
26
27
27
```csharp
28
-
vartestRouteOkCounter=collector.GetMetric(
29
-
"hits",
30
-
"units",
31
-
"description",
28
+
vartestRouteOkCounter=collector.CreateMetric(
29
+
"hits",// metric name
30
+
"http requests", // units
31
+
"description",// meaningful description
32
32
newRouteCounter("Test/Route", true));
33
33
```
34
34
35
35
The metric name `hits` has now been bound to the `RouteCounter` type. If we try to use that metric name with any other type, the library will throw an exception. However, we can use that metric name with as many different instances of `RouteCounter` as we'd like. For example:
36
36
37
37
```csharp
38
-
vartestRouteErrorCounter=collector.GetMetric(
38
+
vartestRouteErrorCounter=collector.CreateMetric(
39
39
"hits",
40
40
"units",
41
41
"description",
42
42
newRouteCounter("Test/Route", false));
43
43
```
44
44
45
-
It it worth noting that the `GetMetric()` method is idempotent, so you'll never end up with duplicate metrics.
45
+
It is worth noting that `CreateMetric()` will throw an exception if you try to create a duplicate metric. That behavior is generally desirable since multiple attempts to create the same metric likely represent a mistake. However, there is also a `GetMetric()` method (with identical signatures) which is idempotent. It still won't allow you to create duplicate metrics, but instead of throwing an exception if an identical metric already exists, it will return the existing metric.
@@ -51,6 +51,6 @@ var two = collector.GetMetric("hits", units, desc, new RouteCounter("Test/Route"
51
51
Console.WriteLine(one==two); // outputs True
52
52
```
53
53
54
-
This, like the rest of the library, is thread safe. You could use this method to always instantiate and use metrics on-demand. Although, if you're concerned with performance, it is computationally cheaper to store the metrics in variables or a hash rather than calling `GetMetric()` every time you need it.
54
+
This, like the rest of the library, is thread safe. You _could_ use this method to always instantiate and use metrics on-demand. However, if you care about performance or allocations, it is cheaper to store the metrics in variables or a hash rather than calling `GetMetric()` every time you need it. Or even better, consider using a [Metric Group](https://github.com/bretcope/BosunReporter.NET/blob/master/docs/MetricGroup.md) to create your metrics.
55
55
56
-
This `RouteCounter` type we just created, and any other BosunMetric type, can be used with as many metric names as you'd like. __You don't have to create a class for every metric you use__ if they share common tag lists. In fact, using common tag lists is a great idea which will help encourage consistency in your metrics conventions.
56
+
> This `RouteCounter` type we just created, and any other BosunMetric type, can be used with as many metric names as you'd like. __You don't have to create a class for every metric you use__ if they share common tag lists. In fact, using common tag lists is a great idea which will help encourage consistency in your metrics conventions.
0 commit comments