public void IfCircuitBreakerBreaksThenNoApiRequestsAreSent()
        {
            var mutex        = new ManualResetEventSlim();
            int logsReceived = 0;

            bool LogsSentCallback(int x)
            {
                Interlocked.Add(ref logsReceived, x);
                mutex.Set();
                return(false);
            }

            var logsApi = new TestLogsApi(LogsSentCallback);
            var options = new BatchingSinkOptions(batchSizeLimit: 2, queueLimit: DefaultQueueLimit, period: TinyWait);
            var sink    = new DatadogSink(logsApi, LogSettingsHelper.GetFormatter(), options);

            sink.Start();

            for (var i = 0; i < BatchingSink.FailuresBeforeCircuitBreak; i++)
            {
                sink.EnqueueLog(new TestLogEvent(DirectSubmissionLogLevel.Debug, "A message"));
                mutex.Wait(10_000).Should().BeTrue();
                mutex.Reset();
            }

            // circuit should be broken
            sink.EnqueueLog(new TestLogEvent(DirectSubmissionLogLevel.Debug, "A message"));
            mutex.Wait(3_000).Should().BeFalse(); // don't expect it to be set

            logsReceived.Should().Be(BatchingSink.FailuresBeforeCircuitBreak);
        }
        public async Task EmitBatchEchoesLogsApiReturnValue(bool logsApiResponse)
        {
            var mutex = new ManualResetEventSlim();

            bool LogsSentCallback(int x)
            {
                mutex.Set();

                return(logsApiResponse);
            }

            var logsApi = new TestLogsApi(LogsSentCallback);
            var options = new BatchingSinkOptions(batchSizeLimit: 2, queueLimit: DefaultQueueLimit, period: TinyWait);
            var sink    = new TestSink(logsApi, LogSettingsHelper.GetFormatter(), options);

            sink.Start();
            var log   = new TestLogEvent(DirectSubmissionLogLevel.Debug, "First message");
            var queue = new Queue <DatadogLogEvent>();

            queue.Enqueue(log);

            var result = await sink.CallEmitBatch(queue);

            result.Should().Be(logsApiResponse);
        }
        public void SinkSendsMessageAsJsonBatch()
        {
            var       mutex         = new ManualResetEventSlim();
            int       logsReceived  = 0;
            const int expectedCount = 2;

            bool LogsSentCallback(int x)
            {
                if (Interlocked.Add(ref logsReceived, x) == expectedCount)
                {
                    mutex.Set();
                }

                return(true);
            }

            var logsApi = new TestLogsApi(LogsSentCallback);
            var options = new BatchingSinkOptions(batchSizeLimit: 2, queueLimit: DefaultQueueLimit, period: TinyWait);
            var sink    = new DatadogSink(logsApi, LogSettingsHelper.GetFormatter(), options);

            sink.Start();

            var firstMessage  = "First message";
            var secondMessage = "Second message";

            sink.EnqueueLog(new TestLogEvent(DirectSubmissionLogLevel.Debug, firstMessage));
            sink.EnqueueLog(new TestLogEvent(DirectSubmissionLogLevel.Information, secondMessage));

            mutex.Wait(TimeSpan.FromSeconds(10)).Should().BeTrue();
            logsApi.Logs.Should().NotBeEmpty();

            var logs = logsApi.Logs
                       .Select(batch => Encoding.UTF8.GetString(batch.Logs.Array))
                       .SelectMany(batch => JsonConvert.DeserializeObject <List <TestLogEvent> >(batch))
                       .ToList();

            logs.Should().NotBeNull();
            logs.Count.Should().Be(2);
            logs[0].Level.Should().Be(DirectSubmissionLogLevel.Debug);
            logs[0].Message.Should().Be(firstMessage);
            logs[1].Level.Should().Be(DirectSubmissionLogLevel.Information);
            logs[1].Message.Should().Be(secondMessage);
        }
        public void SinkSendsMessagesToLogsApi()
        {
            var mutex = new ManualResetEventSlim();

            var logsApi = new TestLogsApi(_ =>
            {
                mutex.Set();
                return(true);
            });
            var options = new BatchingSinkOptions(batchSizeLimit: 2, queueLimit: DefaultQueueLimit, period: TinyWait);
            var sink    = new DatadogSink(logsApi, LogSettingsHelper.GetFormatter(), options);

            sink.Start();

            sink.EnqueueLog(new TestLogEvent(DirectSubmissionLogLevel.Debug, "First message"));

            // Wait for the logs to be sent, should be done in 50ms
            mutex.Wait(TimeSpan.FromSeconds(10)).Should().BeTrue();
            logsApi.Logs.Should().ContainSingle();
        }
        public void SinkSendsMultipleBatches()
        {
            var       mutex         = new ManualResetEventSlim();
            int       logsReceived  = 0;
            const int expectedCount = 5;

            bool LogsSentCallback(int x)
            {
                if (Interlocked.Add(ref logsReceived, x) == expectedCount)
                {
                    mutex.Set();
                }

                return(true);
            }

            var logsApi = new TestLogsApi(LogsSentCallback);
            var options = new BatchingSinkOptions(batchSizeLimit: 2, queueLimit: DefaultQueueLimit, period: TinyWait);
            var sink    = new DatadogSink(logsApi, LogSettingsHelper.GetFormatter(), options);

            sink.Start();

            sink.EnqueueLog(new TestLogEvent(DirectSubmissionLogLevel.Debug, "First message"));
            sink.EnqueueLog(new TestLogEvent(DirectSubmissionLogLevel.Information, "Second message"));
            sink.EnqueueLog(new TestLogEvent(DirectSubmissionLogLevel.Information, "Third message"));
            sink.EnqueueLog(new TestLogEvent(DirectSubmissionLogLevel.Information, "Fourth message"));
            sink.EnqueueLog(new TestLogEvent(DirectSubmissionLogLevel.Information, "Fifth message"));

            mutex.Wait(TimeSpan.FromSeconds(10)).Should().BeTrue();

            logsApi.Logs.Should().HaveCountGreaterOrEqualTo(3); // batch size is 2, so at least 3 batches

            var logs = logsApi.Logs
                       .Select(batch => Encoding.UTF8.GetString(batch.Logs.Array))
                       .SelectMany(batch => JsonConvert.DeserializeObject <List <TestLogEvent> >(batch))
                       .ToList();

            logs.Count.Should().Be(5);
            logs.Select(x => x.Message).Should().OnlyHaveUniqueItems();
        }
        public void SinkRejectsGiantMessages()
        {
            var mutex = new ManualResetEventSlim();

            var logsApi = new TestLogsApi();
            var options = new BatchingSinkOptions(batchSizeLimit: 2, queueLimit: DefaultQueueLimit, period: TinyWait);
            var sink    = new DatadogSink(
                logsApi,
                LogSettingsHelper.GetFormatter(),
                options,
                oversizeLogCallback: _ => mutex.Set(),
                sinkDisabledCallback: () => { });

            sink.Start();

            var message = new StringBuilder().Append('x', repeatCount: 1024 * 1024).ToString();

            sink.EnqueueLog(new TestLogEvent(DirectSubmissionLogLevel.Debug, message));

            // Wait for the logs to be sent, should be done in 50ms
            mutex.Wait(TimeSpan.FromSeconds(10)).Should().BeTrue();
            logsApi.Logs.Should().BeEmpty();
        }