public static void Metrics_Not_Sent_If_Array_Is_Null_Or_Empty()
        {
            // Arrange
            var mock   = new Mock <IStatsDTransport>();
            var config = new StatsDConfiguration();

            using (var publisher = new StatsDPublisher(config, mock.Object))
            {
                // Act
#nullable disable
                publisher.Decrement(-1, 1, null as string[]);
                publisher.Increment(-1, 1, null as string[]);
                publisher.Decrement(1, 1, null as string[]);
                publisher.Increment(1, 1, null as string[]);
                publisher.Decrement(1, 1, Array.Empty <string>());
                publisher.Increment(1, 1, Array.Empty <string>());
                publisher.Decrement(-1, 1, Array.Empty <string>());
                publisher.Increment(-1, 1, Array.Empty <string>());
                publisher.Decrement(-1, 1, new List <string>());
                publisher.Increment(-1, 1, new List <string>());
                publisher.Decrement(1, 1, null as IEnumerable <string>);
                publisher.Increment(1, 1, null as IEnumerable <string>);
                publisher.Decrement(1, 1, new[] { string.Empty });
                publisher.Increment(1, 1, new[] { string.Empty });
#nullable enable
            }
        public void ConfigurationIsNull()
        {
            StatsDConfiguration noConfig = null;

            Should.Throw <ArgumentNullException>(
                () => new StatsDPublisher(noConfig));
        }
        public static void Increment_Sends_Multiple_Metrics()
        {
            // Arrange
            var mock = new Mock <IStatsDTransport>();

            var config = new StatsDConfiguration
            {
                Prefix = "red",
            };

            using (var publisher = new StatsDPublisher(config, mock.Object))
            {
                // Act
                publisher.Increment(10, "black");
                publisher.Increment(-10, "yellow");
                publisher.Increment(10, 1, "pink");
                publisher.Increment(-10, 1, "orange");
                publisher.Increment(10, 1, new[] { "white", "blue" });
                publisher.Increment(10, 1, new List <string>()
                {
                    "green", "red"
                });
                publisher.Increment(10, 1, null as IEnumerable <string>);
            }

            // Assert
            mock.Verify((p) => p.Send(It.Ref <ArraySegment <byte> > .IsAny), Times.Exactly(8));
        }
        public static void Metrics_Not_Sent_If_Array_Is_Null_Or_Empty()
        {
            // Arrange
            var mock   = new Mock <IStatsDTransport>();
            var config = new StatsDConfiguration();

            using (var publisher = new StatsDPublisher(config, mock.Object))
            {
                // Act
                publisher.Decrement(-1, 1, null as string[]);
                publisher.Increment(-1, 1, null as string[]);
                publisher.Decrement(1, 1, null as string[]);
                publisher.Increment(1, 1, null as string[]);
                publisher.Decrement(1, 1, Array.Empty <string>());
                publisher.Increment(1, 1, Array.Empty <string>());
                publisher.Decrement(-1, 1, Array.Empty <string>());
                publisher.Increment(-1, 1, Array.Empty <string>());
                publisher.Decrement(-1, 1, new List <string>());
                publisher.Increment(-1, 1, new List <string>());
                publisher.Decrement(1, 1, null as IEnumerable <string>);
                publisher.Increment(1, 1, null as IEnumerable <string>);
                publisher.Decrement(1, 1, new[] { string.Empty });
                publisher.Increment(1, 1, new[] { string.Empty });
            }

            // Assert
            mock.Verify((p) => p.Send(It.IsAny <ArraySegment <byte> >()), Times.Never());
        }
        private static async Task AssertMetrics(StatsDConfiguration config, IStatsDPublisher publisher)
        {
            // Act - Create a counter
            publisher.Increment("apple");

            // Act - Create and change a counter
            publisher.Increment("bear");        // 1
            publisher.Increment(10, "bear");    // 11
            publisher.Increment(10, 0, "bear"); // 11
            publisher.Decrement("bear");        // 10
            publisher.Decrement(5, "bear");     // 5
            publisher.Decrement(5, 0, "bear");  // 5

            // Act - Mark an event (which is a counter)
            publisher.Increment("fish");

            // Act - Create a gauge
            publisher.Gauge(3.141, "circle");

            // Act - Create and change a gauge
            publisher.Gauge(10, "dog");
            publisher.Gauge(42, "dog");

            // Act - Create a timer
            publisher.Timing(123, "elephant");
            publisher.Timing(TimeSpan.FromSeconds(2), "fox");
            publisher.Timing(456, 1, "goose");
            publisher.Timing(TimeSpan.FromSeconds(3.5), 1, "hen");

            // Act - Increment multiple counters
            publisher.Increment(7, 1, "green", "red"); // 7
            publisher.Increment(2, 0, "green", "red"); // 7
            publisher.Decrement(1, 0, "red", "green"); // 7
            publisher.Decrement(4, 1, "red", "green"); // 3

            // Allow enough time for metrics to be registered
            await Task.Delay(TimeSpan.FromSeconds(1.0));

            // Assert
            var result = await SendCommandAsync("counters");

            result.Value <int>(config.Prefix + ".apple").ShouldBe(1, result.ToString());
            result.Value <int>(config.Prefix + ".bear").ShouldBe(5, result.ToString());
            result.Value <int>(config.Prefix + ".fish").ShouldBe(1, result.ToString());
            result.Value <int>(config.Prefix + ".green").ShouldBe(3, result.ToString());
            result.Value <int>(config.Prefix + ".red").ShouldBe(3, result.ToString());

            result = await SendCommandAsync("gauges");

            result.Value <double>(config.Prefix + ".circle").ShouldBe(3.141, result.ToString());
            result.Value <int>(config.Prefix + ".dog").ShouldBe(42, result.ToString());

            result = await SendCommandAsync("timers");

            result[config.Prefix + ".elephant"].Values <int>().ShouldBe(new[] { 123 }, result.ToString());
            result[config.Prefix + ".fox"].Values <int>().ShouldBe(new[] { 2000 }, result.ToString());
            result[config.Prefix + ".goose"].Values <int>().ShouldBe(new[] { 456 }, result.ToString());
            result[config.Prefix + ".hen"].Values <int>().ShouldBe(new[] { 3500 }, result.ToString());
        }
        public void ConfigurationIsNull()
        {
            StatsDConfiguration configuration = null;

            Assert.Throws <ArgumentNullException>(
                "configuration",
                () => new StatsDPublisher(configuration));
        }
        public void ConfigurationIsValidWithHostIp()
        {
            var validConfig = new StatsDConfiguration
            {
                Host = "10.0.1.2"
            };

            using var stats = new StatsDPublisher(validConfig);
        }
        public void ConfigurationHasNoHost()
        {
            var badConfig = new StatsDConfiguration
            {
                Host = null
            };

            Should.Throw <ArgumentNullException>(
                () => new StatsDPublisher(badConfig));
        }
        public static void Constructor_Throws_If_Transport_Is_Null()
        {
            // Arrange
            var configuration          = new StatsDConfiguration();
            IStatsDTransport transport = null;

            // Act and Assert
            Assert.Throws <ArgumentNullException>(
                "transport",
                () => new StatsDPublisher(configuration, transport));
        }
예제 #10
0
        public static void Constructor_Throws_If_Configuration_Is_Null()
        {
            // Arrange
            StatsDConfiguration configuration = null;
            var transport = Mock.Of <IStatsDTransport>();

            // Act and Assert
            Assert.Throws <ArgumentNullException>(
                "configuration",
                () => new StatsDPublisher(configuration, transport));
        }
        public void ConfigurationHasNoHost()
        {
            var configuration = new StatsDConfiguration
            {
                Host = null
            };

            Assert.Throws <ArgumentException>(
                "configuration",
                () => new StatsDPublisher(configuration));
        }
        public void ConfigurationHasNoCulture()
        {
            var badConfig = new StatsDConfiguration
            {
                Host    = "someserver.somewhere.com",
                Culture = null
            };

            Should.Throw <ArgumentNullException>(
                () => new StatsDPublisher(badConfig));
        }
예제 #13
0
        public StatsDPublisher(StatsDConfiguration configuration, IStatsDTransport transport)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            _transport = transport ?? throw new ArgumentNullException(nameof(transport));

            _formatter = new StatsDMessageFormatter(configuration.Culture, configuration.Prefix);
        }
        public void ConfigurationIsValidWithHostName()
        {
            var validConfig = new StatsDConfiguration
            {
                Host = "someserver.somewhere.com"
            };

            using (new StatsDPublisher(validConfig))
            {
            }
        }
        public void ConfigurationIsValidWithHostName()
        {
            var validConfig = new StatsDConfiguration
            {
                Host = "someserver.somewhere.com"
            };

            var stats = new StatsDPublisher(validConfig);

            stats.ShouldNotBeNull();
        }
        public void ConfigurationIsValidWithHostIp()
        {
            var validConfig = new StatsDConfiguration
            {
                Host = "10.0.1.2"
            };

            var stats = new StatsDPublisher(validConfig);

            stats.ShouldNotBeNull();
        }
        public void ItShouldBeAbleToSendMessagesOfArbitraryLength(char ch, int count)
        {
            var config = new StatsDConfiguration
            {
                Host = "127.0.0.1"
            };

            var fakeTransport = new FakeTransport();
            var publisher     = new BufferBasedStatsDPublisher(config, fakeTransport);

            publisher.Increment(new string(ch, count));
            fakeTransport.TimesCalled.ShouldBe(1);
        }
예제 #18
0
        public static void Metrics_Not_Sent_If_No_Metrics()
        {
            // Arrange
            var mock   = new Mock <IStatsDTransport>();
            var config = new StatsDConfiguration();

            var publisher = new StatsDPublisher(config, mock.Object);

            // Act
            publisher.Decrement(1, 0, new[] { "foo" });
            publisher.Increment(1, 0, new[] { "bar" });

            // Assert
            mock.Verify((p) => p.Send(It.IsAny <ArraySegment <byte> >()), Times.Never());
        }
예제 #19
0
        /// <summary>
        /// Initializes a new instance of the <see cref="StatsDPublisher"/> class for the specified transport.
        /// </summary>
        /// <param name="configuration">The StatsD configuration to use.</param>
        /// <param name="transport">The transport implementation to use.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="configuration"/> or <paramref name="transport"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="configuration"/> is invalid, such as an invalid hostname or IP address.
        /// </exception>
        public StatsDPublisher(StatsDConfiguration configuration, IStatsDTransport transport)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            if (transport == null)
            {
                throw new ArgumentNullException(nameof(transport));
            }

            _inner = new BufferBasedStatsDPublisher(configuration, transport);

            _transport        = transport;
            _disposeTransport = false;
        }
        public static void Decrement_Sends_Multiple_Metrics()
        {
            // Arrange
            var mock = new Mock <IStatsDTransport>();

            var config = new StatsDConfiguration
            {
                Prefix = "red",
            };

            var publisher = new StatsDPublisher(config, mock.Object);

            // Act
            publisher.Decrement(10, 1, "white", "blue");

            // Assert
            mock.Verify((p) => p.Send(It.Ref <ArraySegment <byte> > .IsAny), Times.Exactly(2));
        }
예제 #21
0
        public static async Task Can_Send_Metrics_To_StatsD_Using_Udp(
            string host,
            SocketProtocol socketProtocol)
        {
            Skip.If(Environment.GetEnvironmentVariable("CI") == null, "By default, this test is only run during continuous integration.");

            // Arrange
            var config = new StatsDConfiguration
            {
                Host           = host,
                Prefix         = Guid.NewGuid().ToString().Replace("-", string.Empty, StringComparison.Ordinal),
                SocketProtocol = socketProtocol,
            };

            using var publisher = new StatsDPublisher(config);

            // Act and Assert
            await AssertMetrics(config, publisher);
        }
예제 #22
0
        public StatsDPublisher(StatsDConfiguration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            if (string.IsNullOrWhiteSpace(configuration.Host))
            {
                throw new ArgumentNullException(nameof(configuration.Host));
            }

            _formatter = new StatsDMessageFormatter(configuration.Culture, configuration.Prefix);

            var endpointSource = EndpointParser.MakeEndPointSource(
                configuration.Host, configuration.Port, configuration.DnsLookupInterval);

            _transport = new UdpTransport(endpointSource);
        }
예제 #23
0
        public static void CanRegisterServicesWithNoConfiguratonIfConfigurationAlreadRegistered()
        {
            // Arrange
            var config = new StatsDConfiguration()
            {
                Host = "localhost"
            };

            var provider = Configure(
                (services) =>
            {
                services.AddSingleton(config);

                // Act
                services.AddStatsD();
            });

            try
            {
                // Assert
                var configuration = provider.GetRequiredService <StatsDConfiguration>();
                configuration.ShouldNotBeNull();
                configuration.ShouldBe(config);

                var source = provider.GetRequiredService <IPEndPointSource>();
                source.ShouldNotBeNull();

                var transport = provider.GetRequiredService <IStatsDTransport>();
                transport.ShouldNotBeNull();
                transport.ShouldBeOfType <UdpTransport>();

                var publisher = provider.GetRequiredService <IStatsDPublisher>();
                publisher.ShouldNotBeNull();
                publisher.ShouldBeOfType <StatsDPublisher>();
            }
            finally
            {
                if (provider is IDisposable disposable)
                {
                    disposable.Dispose();
                }
            }
        }
예제 #24
0
        /// <summary>
        /// Initializes a new instance of the <see cref="StatsDPublisher"/> class using the default transport.
        /// </summary>
        /// <param name="configuration">The StatsD configuration to use.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="configuration"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="configuration"/> is invalid, such as an invalid hostname or IP address.
        /// </exception>
        public StatsDPublisher(StatsDConfiguration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            if (string.IsNullOrWhiteSpace(configuration.Host))
            {
                throw new ArgumentException("No hostname or IP address is set.", nameof(configuration));
            }

            var endpointSource = EndPointFactory.MakeEndPointSource(
                configuration.Host !, configuration.Port, configuration.DnsLookupInterval);

            var transport = new SocketTransport(endpointSource, configuration.SocketProtocol);

            _transport        = transport;
            _disposeTransport = true;

            _inner = new BufferBasedStatsDPublisher(configuration, transport);
        }
예제 #25
0
        public static void RegisteringServicesDoesNotOverwriteExistingRegistrations()
        {
            // Arrange
            var existingConfig    = new StatsDConfiguration();
            var existingSource    = Mock.Of <IPEndPointSource>();
            var existingTransport = Mock.Of <IStatsDTransport>();
            var existingPublisher = Mock.Of <IStatsDPublisher>();

            var provider = Configure(
                (services) =>
            {
                services.AddSingleton(existingConfig);
                services.AddSingleton(existingSource);
                services.AddSingleton(existingTransport);
                services.AddSingleton(existingPublisher);

                // Act
                services.AddStatsD();
            });

            // Assert
            var configuration = provider.GetRequiredService <StatsDConfiguration>();

            configuration.ShouldBe(existingConfig);

            var source = provider.GetRequiredService <IPEndPointSource>();

            source.ShouldBe(existingSource);

            var transport = provider.GetRequiredService <IStatsDTransport>();

            transport.ShouldBe(existingTransport);

            var publisher = provider.GetRequiredService <IStatsDPublisher>();

            publisher.ShouldBe(existingPublisher);
        }
예제 #26
0
 private static IStatsDPublisher MakeThrowingPublisher(StatsDConfiguration config)
 {
     return(new StatsDPublisher(config, new ThrowingTransport()));
 }
예제 #27
0
        private static async Task AssertMetrics(StatsDConfiguration config, IStatsDPublisher publisher)
        {
            // Act - Create a counter
            publisher.Increment("apple");

            // Act - Create and change a counter
            publisher.Increment("bear");              // 1
            publisher.Increment(10, "bear");          // 11
            publisher.Increment(10, 0, "bear", null); // 11
            publisher.Decrement("bear");              // 10
            publisher.Decrement(5, "bear");           // 5
            publisher.Decrement(5, 0, "bear");        // 5

            // Act - Create and change a counter with tags
            Dictionary<string, string> tags = new Dictionary<string, string>();
            tags.Add("key", "value");
            tags.Add("key2", "value2");
            publisher.Increment("ant", tags);              // 1
            publisher.Increment(15, "ant", tags);          // 16
            publisher.Decrement(5,"ant", tags);            // 11

            // Act - Create multiple counters with tags and change them
            tags = new Dictionary<string, string>();
            tags.Add("key", "value");
            tags.Add("key2", "value2");
            publisher.Increment(100, 1, tags, new string[] { "gmc", "ford" });        // 100
            publisher.Decrement(5, 1, tags, new string[] { "gmc", "ford" });          // 95

            // Act - Create multiple counters without tags and change them
            publisher.Increment(150, 1, null, new string[] { "jaguar", "kia" });      // 100
            publisher.Decrement(20, 1, null, new string[] { "jaguar", "kia" });       // 130

            // Act - Create a counter with tags
            tags = new Dictionary<string, string>();
            tags.Add("key", "value");
            tags.Add("key2", "value2");
            publisher.Increment("orange", tags);      // 1
            publisher.Increment(50, "orange", tags);  // 51

            // Act - Create multiple counters with tags
            tags = new Dictionary<string, string>();
            tags.Add("type", "vehicle");
            publisher.Increment(60, 1, tags, new string[] { "mazda", "fiat" });

            // Act - Create multiple counters without tags
            publisher.Increment(25, 1, null, new string[] { "ferrari", "jeep" });

            // Act - Mark an event (which is a counter)
            publisher.Increment("fish");

            // Act - Create a gauge
            publisher.Gauge(3.141, "circle", Operation.Set, null);

            // Act - Create and change a gauge
            publisher.Gauge(10, "dog", Operation.Set, null);
            publisher.Gauge(42, "dog", Operation.Set, null);

            // Act - Create a gauge with tags
            tags = new Dictionary<string, string>();
            tags.Add("foo", "bar");
            tags.Add("lorem", "ipsum");
            publisher.Gauge(5.5, "square", Operation.Set, tags);

            // Act - Create a gauge and decrement it
            publisher.Gauge(2020, "year", Operation.Set, null);
            publisher.Gauge(10, "year", Operation.Decrement, null);

            // Act - Create a gauge and increment it
            publisher.Gauge(15, "score", Operation.Set, null);
            publisher.Gauge(2, "score", Operation.Increment, null);

            // Act - Create a timer
            publisher.Timing(123, "elephant");
            publisher.Timing(TimeSpan.FromSeconds(2), "fox");
            publisher.Timing(456, 1, "goose", null);
            publisher.Timing(TimeSpan.FromSeconds(3.5), 1, "hen");

            // Act - Create a timer with tags
            tags = new Dictionary<string, string>();
            tags.Add("class", "mammal");
            tags.Add("genus", "panthera");
            publisher.Timing(128, "leopard", tags);

            // Act - Increment multiple counters
            publisher.Increment(7, 1, new string[] { "green", "red" });       // 7
            publisher.Increment(2, 0, new List<string>() { "green", "red" }); // 7
            publisher.Decrement(1, 0, new string[] { "red", "green" });       // 7
            publisher.Decrement(4, 1, new List<string>() { "red", "green" }); // 3

            // Allow enough time for metrics to be registered
            await Task.Delay(TimeSpan.FromSeconds(1.0));

            // Assert
            var result = await SendCommandAsync("counters");
            result.Value<int>(config.Prefix + ".apple").ShouldBe(1, result.ToString());
            result.Value<int>(config.Prefix + ".bear").ShouldBe(5, result.ToString());
            result.Value<int>(config.Prefix + ".ant;key=value;key2=value2").ShouldBe(11, result.ToString());
            result.Value<int>(config.Prefix + ".gmc;key=value;key2=value2").ShouldBe(95, result.ToString());
            result.Value<int>(config.Prefix + ".ford;key=value;key2=value2").ShouldBe(95, result.ToString());
            result.Value<int>(config.Prefix + ".jaguar").ShouldBe(130, result.ToString());
            result.Value<int>(config.Prefix + ".kia").ShouldBe(130, result.ToString());
            result.Value<int>(config.Prefix + ".orange;key=value;key2=value2").ShouldBe(51, result.ToString());
            result.Value<int>(config.Prefix + ".mazda;type=vehicle").ShouldBe(60, result.ToString());
            result.Value<int>(config.Prefix + ".fiat;type=vehicle").ShouldBe(60, result.ToString());
            result.Value<int>(config.Prefix + ".ferrari").ShouldBe(25, result.ToString());
            result.Value<int>(config.Prefix + ".jeep").ShouldBe(25, result.ToString());
            result.Value<int>(config.Prefix + ".fish").ShouldBe(1, result.ToString());
            result.Value<int>(config.Prefix + ".green").ShouldBe(3, result.ToString());
            result.Value<int>(config.Prefix + ".red").ShouldBe(3, result.ToString());

            result = await SendCommandAsync("gauges");
            result.Value<double>(config.Prefix + ".circle").ShouldBe(3.141, result.ToString());
            result.Value<int>(config.Prefix + ".dog").ShouldBe(42, result.ToString());
            result.Value<double>(config.Prefix + ".square;foo=bar;lorem=ipsum").ShouldBe(5.5, result.ToString());
            result.Value<int>(config.Prefix + ".year").ShouldBe(2010, result.ToString());
            result.Value<int>(config.Prefix + ".score").ShouldBe(17, result.ToString());

            result = await SendCommandAsync("timers");
            result[config.Prefix + ".elephant"].Values<int>().ShouldBe(new[] { 123 }, result.ToString());
            result[config.Prefix + ".leopard;class=mammal;genus=panthera"].Values<int>().ShouldBe(new[] { 128 }, result.ToString());
            result[config.Prefix + ".fox"].Values<int>().ShouldBe(new[] { 2000 }, result.ToString());
            result[config.Prefix + ".goose"].Values<int>().ShouldBe(new[] { 456 }, result.ToString());
            result[config.Prefix + ".hen"].Values<int>().ShouldBe(new[] { 3500 }, result.ToString());
        }