public MetricsCollector(BosunOptions options) { MetricsNamePrefix = options.MetricsNamePrefix ?? ""; if (MetricsNamePrefix != "" && !BosunValidation.IsValidMetricName(MetricsNamePrefix)) { throw new Exception("\"" + MetricsNamePrefix + "\" is not a valid metric name prefix."); } GetBosunUrl = options.GetBosunUrl; BosunUrl = GetBosunUrl == null ? options.BosunUrl : GetBosunUrl(); MaxQueueLength = options.MaxQueueLength; BatchSize = options.BatchSize; ThrowOnPostFail = options.ThrowOnPostFail; ThrowOnQueueFull = options.ThrowOnQueueFull; ReportingInterval = options.ReportingInterval; PropertyToTagName = options.PropertyToTagName; TagValueConverter = options.TagValueConverter; DefaultTags = ValidateDefaultTags(options.DefaultTags); // start continuous queue-flushing _flushTimer = new Timer(Flush, true, 1000, 1000); // start reporting timer var interval = TimeSpan.FromSeconds(ReportingInterval); _reportingTimer = new Timer(Snapshot, true, interval, interval); // metadata timer - wait 30 seconds to start (so there is some time for metrics to be delcared) if (options.MetaDataReportingInterval > 0) { _metaDataTimer = new Timer(PostMetaData, true, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(options.MetaDataReportingInterval)); } }
/// <summary> /// Instantiates a new collector (the primary class of BosunReporter). You should typically only instantiate one collector for the lifetime of your /// application. It will manage the serialization of metrics and sending data to Bosun. /// </summary> /// <param name="options"></param> /// <param name="exceptionHandler"></param> public MetricsCollector(BosunOptions options, Action <Exception> exceptionHandler) { if (exceptionHandler == null) { throw new ArgumentNullException(nameof(exceptionHandler)); } ExceptionHandler = exceptionHandler; _localMetricsQueue = new PayloadQueue(QueueType.Local); _externalCounterQueue = new PayloadQueue(QueueType.ExternalCounters); _localMetricsQueue.PayloadDropped += OnPayloadDropped; _externalCounterQueue.PayloadDropped += OnPayloadDropped; // these two setters actually update the queues themselves MaxPayloadSize = options.MaxPayloadSize; MaxPendingPayloads = options.MaxPendingPayloads; MetricsNamePrefix = options.MetricsNamePrefix ?? ""; if (MetricsNamePrefix != "" && !BosunValidation.IsValidMetricName(MetricsNamePrefix)) { throw new Exception("\"" + MetricsNamePrefix + "\" is not a valid metric name prefix."); } GetBosunUrl = options.GetBosunUrl; BosunUrl = GetBosunUrl == null ? options.BosunUrl : GetBosunUrl(); _accessToken = options.AccessToken; _getAccessToken = options.GetAccessToken; ThrowOnPostFail = options.ThrowOnPostFail; ThrowOnQueueFull = options.ThrowOnQueueFull; ReportingInterval = options.ReportingInterval; EnableExternalCounters = options.EnableExternalCounters; PropertyToTagName = options.PropertyToTagName; TagValueConverter = options.TagValueConverter; DefaultTags = ValidateDefaultTags(options.DefaultTags); // start continuous queue-flushing _flushTimer = new Timer(Flush, true, 1000, 1000); // start reporting timer var interval = TimeSpan.FromSeconds(ReportingInterval); _reportingTimer = new Timer(Snapshot, true, interval, interval); // metadata timer - wait 30 seconds to start (so there is some time for metrics to be delcared) if (options.MetaDataReportingInterval > 0) { _metaDataTimer = new Timer(PostMetaData, true, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(options.MetaDataReportingInterval)); } }
/// <summary> /// Instantiates a new collector (the primary class of BosunReporter). You should typically only instantiate one collector for the lifetime of your /// application. It will manage the serialization of metrics and sending data to Bosun. /// </summary> /// <param name="options"></param> public MetricsCollector(BosunOptions options) { ExceptionHandler = options.ExceptionHandler; if (options.SnapshotInterval < TimeSpan.FromSeconds(1)) { throw new InvalidOperationException("options.SnapshotInterval cannot be less than one second"); } _localMetricsQueue = new PayloadQueue(QueueType.Local); _externalCounterQueue = new PayloadQueue(QueueType.ExternalCounters); _localMetricsQueue.PayloadDropped += OnPayloadDropped; _externalCounterQueue.PayloadDropped += OnPayloadDropped; // these two setters actually update the queues themselves MaxPayloadSize = options.MaxPayloadSize; MaxPendingPayloads = options.MaxPendingPayloads; MetricsNamePrefix = options.MetricsNamePrefix ?? ""; if (MetricsNamePrefix != "" && !BosunValidation.IsValidMetricName(MetricsNamePrefix)) { throw new Exception("\"" + MetricsNamePrefix + "\" is not a valid metric name prefix."); } _getUrlDynamic = options.GetBosunUrl; _fixedUrl = options.BosunUrl; _accessToken = options.AccessToken; _getAccessToken = options.GetAccessToken; ThrowOnPostFail = options.ThrowOnPostFail; ThrowOnQueueFull = options.ThrowOnQueueFull; ReportingInterval = options.SnapshotInterval; EnableExternalCounters = options.EnableExternalCounters; PropertyToTagName = options.PropertyToTagName; TagValueConverter = options.TagValueConverter; DefaultTags = ValidateDefaultTags(options.DefaultTags); // start continuous queue-flushing _flushTimer = new Timer(Flush, true, 1000, 1000); // start reporting timer _reportingTimer = new Timer(Snapshot, true, ReportingInterval, ReportingInterval); }
static void Main(string[] args) { Debug.Listeners.Add(new TextWriterTraceListener(Console.Out)); Debug.AutoFlush = true; Func<Uri> getUrl = () => { return new Uri("http://192.168.99.100:8070/"); }; // for testing minimum event threshold // AggregateGauge.GetDefaultMinimumEvents = () => 306000; var options = new BosunOptions() { MetricsNamePrefix = "bret.", GetBosunUrl = getUrl, ThrowOnPostFail = true, ReportingInterval = 5, PropertyToTagName = NameTransformers.CamelToLowerSnakeCase, TagValueConverter = (name, value) => name == "converted" ? value.ToLowerInvariant() : value, DefaultTags = new Dictionary<string, string> { {"host", NameTransformers.Sanitize(Environment.MachineName.ToLower())} } }; var collector = new MetricsCollector(options); collector.OnBackgroundException += exception => { Console.WriteLine("Hey, there was an exception."); Console.WriteLine(exception); }; collector.BeforeSerialization += () => Debug.WriteLine("BosunReporter: Running metrics snapshot."); collector.AfterSerialization += info => Debug.WriteLine($"BosunReporter: Metric Snapshot took {info.MillisecondsDuration.ToString("0.##")}ms"); collector.AfterPost += info => Debug.WriteLine($"BosunReporter: {info.Count} metrics posted to Bosun in {info.MillisecondsDuration.ToString("0.##")}ms ({(info.Successful ? "SUCCESS" : "FAILED")})"); collector.BindMetric("my_counter", "increments", typeof(TestCounter)); var counter = collector.GetMetric<TestCounter>("my_counter", "increments", "This is meaningless."); counter.Increment(); counter.Increment(); var gauge = collector.CreateMetric("gauge", "watts", "Some description of a gauge.", new TestAggregateGauge("1")); if (gauge != collector.GetMetric("gauge", "watts", null, new TestAggregateGauge("1"))) throw new Exception("WAT?"); try { collector.CreateMetric("gauge", "watts", "Some description of a gauge.", new TestAggregateGauge("1")); } catch(Exception) { goto SKIP_EXCEPTION; } throw new Exception("CreateMetric should have failed for duplicate metric."); SKIP_EXCEPTION: var gauge2 = collector.GetMetric<AggregateGauge>("gauge2", "newtons", "Number of newtons currently applied."); for (var i = 0; i < 6; i++) { new Thread(Run).Start(new Tuple<AggregateGauge, AggregateGauge, int>(gauge, gauge2, i)); } var enumCounter = collector.GetMetricGroup<SomeEnum, EnumCounter>("some_enum", "things", "Some of something"); enumCounter.PopulateFromEnum(); Type t; string u; if (collector.TryGetMetricInfo("gauge2", out t, out u)) { Console.WriteLine(t); Console.WriteLine(u); } else { Console.WriteLine("NOOOOO!!!!!"); } var si = 0; var snapshot = collector.GetMetric("my_snapshot", "snappys", "Snap snap snap.", new SnapshotGauge(() => ++si % 5)); var group = collector.GetMetricGroup<string, TestGroupGauge>("test_group", "tests", "These gauges are for testing."); group.Add("low").Description = "Low testing."; group.Add("medium").Description = "Medium testing."; group.Add("high").Description = "High testing."; var sampler = collector.GetMetric("sampler", "french fries", "Collect them all.", new SamplingGauge()); var eventGauge = collector.GetMetric("event", "count", "How many last time.", new EventGauge()); var converted = collector.CreateMetric("convert_test", "units", "Checking to see if the tag value converter works.", new ConvertedTagsTestCounter("ThingsAndStuff")); var sai = 0; var random = new Random(); _samplerTimer = new Timer(o => { sampler.Record(++sai%35); eventGauge.Record(sai%35); group["low"].Record(random.Next(0, 10)); group["medium"].Record(random.Next(10, 20)); group["high"].Record(random.Next(20, 30)); enumCounter[SomeEnum.One].Increment(); enumCounter[SomeEnum.Two].Increment(2); enumCounter[SomeEnum.Three].Increment(3); enumCounter[SomeEnum.Four].Increment(4); converted.Increment(); if (sai == 40) { collector.Shutdown(); Environment.Exit(0); } }, null, 1000, 1000); Thread.Sleep(4000); collector.UpdateDefaultTags(new Dictionary<string, string> { { "host", NameTransformers.Sanitize(Environment.MachineName.ToLower()) } }); // Thread.Sleep(4000); // collector.UpdateDefaultTags(new Dictionary<string, string>() { { "host", "test_env" } }); }