Example #1
0
        public Fixture()
        {
            Hub    = Substitute.For <IHub>();
            Tracer = new TransactionTracer(Hub, "foo", "bar")
            {
                IsSampled = true
            };
            _scope = new Scope
            {
                Transaction = Tracer
            };

            var logger = Substitute.For <IDiagnosticLogger>();

            logger.IsEnabled(Arg.Any <SentryLevel>()).Returns(true);

            Options = new SentryOptions
            {
                TracesSampleRate = 1.0,
                Debug            = true,
                DiagnosticLogger = logger
            };
            Hub.GetSpan().ReturnsForAnyArgs(_ => Spans?.LastOrDefault(s => !s.IsFinished) ?? Tracer);
            Hub.CaptureEvent(Arg.Any <SentryEvent>(), Arg.Any <Scope>()).Returns(_ =>
            {
                Spans.LastOrDefault(s => !s.IsFinished)?.Finish(SpanStatus.InternalError);
                return(SentryId.Empty);
            });
            Hub.When(hub => hub.ConfigureScope(Arg.Any <Action <Scope> >()))
            .Do(callback => callback.Arg <Action <Scope> >().Invoke(_scope));
        }
Example #2
0
        public async Task SendAsync_ExceptionThrown_ExceptionLinkedToSpan()
        {
            // Arrange
            var hub = Substitute.For <IHub>();

            var transaction = new TransactionTracer(
                hub,
                "foo",
                "bar"
                );

            hub.GetSpan().ReturnsForAnyArgs(transaction);

            var exception = new Exception();

            using var innerHandler  = new FakeHttpMessageHandler(() => throw exception);
            using var sentryHandler = new SentryHttpMessageHandler(innerHandler, hub);
            using var client        = new HttpClient(sentryHandler);

            // Act
            await Assert.ThrowsAsync <Exception>(() => client.GetAsync("https://example.com/"));

            // Assert
            hub.Received(1).BindException(exception, Arg.Any <ISpan>()); // second argument is an implicitly created span
        }
Example #3
0
        public void Finish_LinksExceptionToEvent()
        {
            // Arrange
            var client  = Substitute.For <ISentryClient>();
            var options = new SentryOptions {
                Dsn = DsnSamples.ValidDsnWithoutSecret
            };
            var hub = new Hub(options, client);

            var exception   = new InvalidOperationException();
            var transaction = new TransactionTracer(hub, "my name", "my op");

            // Act
            transaction.Finish(exception);

            var @event = new SentryEvent(exception);

            hub.CaptureEvent(@event);

            // Assert
            transaction.Status.Should().Be(SpanStatus.InternalError);

            client.Received(1).CaptureEvent(Arg.Is <SentryEvent>(e =>
                                                                 e.Contexts.Trace.TraceId == transaction.TraceId &&
                                                                 e.Contexts.Trace.SpanId == transaction.SpanId &&
                                                                 e.Contexts.Trace.ParentSpanId == transaction.ParentSpanId
                                                                 ), Arg.Any <Scope>());
        }
Example #4
0
    public async Task SendAsync_TransactionOnScope_StartsNewSpan()
    {
        // Arrange
        var hub = Substitute.For <IHub>();

        var transaction = new TransactionTracer(
            hub,
            "foo",
            "bar");

        hub.GetSpan().ReturnsForAnyArgs(transaction);

        using var innerHandler  = new FakeHttpMessageHandler();
        using var sentryHandler = new SentryHttpMessageHandler(innerHandler, hub);
        using var client        = new HttpClient(sentryHandler);

        // Act
        await client.GetAsync("https://localhost/");

        // Assert
        transaction.Spans.Should().Contain(span =>
                                           span.Operation == "http.client" &&
                                           span.Description == "GET https://localhost/" &&
                                           span.IsFinished);
    }
Example #5
0
        public void Finish_DropsUnfinishedSpans()
        {
            // Arrange
            var client = Substitute.For <ISentryClient>();
            var hub    = new Hub(new SentryOptions {
                Dsn = DsnSamples.ValidDsnWithoutSecret
            }, client);

            var transaction = new TransactionTracer(hub, "my name", "my op");

            transaction.StartChild("op1").Finish();
            transaction.StartChild("op2");
            transaction.StartChild("op3").Finish();

            // Act
            transaction.Finish();

            // Assert
            client.Received(1).CaptureTransaction(
                Arg.Is <Transaction>(t =>
                                     t.Spans.Count == 2 &&
                                     t.Spans.Any(s => s.Operation == "op1") &&
                                     t.Spans.All(s => s.Operation != "op2") &&
                                     t.Spans.Any(s => s.Operation == "op3")
                                     )
                );
        }
Example #6
0
            public ITransaction StartTransaction(IHub hub, ITransactionContext context)
            {
                var transaction = new TransactionTracer(hub, context);

                transaction.IsSampled    = true;
                var(currentScope, _)     = ScopeManager.GetCurrent();
                currentScope.Transaction = transaction;
                return(transaction);
            }
Example #7
0
        public void Finish_NoStatus_DefaultsToUnknown()
        {
            // Arrange
            var hub         = Substitute.For <IHub>();
            var transaction = new TransactionTracer(hub, "my name", "my op");

            // Act
            transaction.Finish();

            // Assert
            transaction.Status.Should().Be(SpanStatus.UnknownError);
        }
Example #8
0
        public void Finish_RecordsTime()
        {
            // Arrange
            var transaction = new TransactionTracer(DisabledHub.Instance, "my name", "my op");

            // Act
            transaction.Finish();

            // Assert
            transaction.EndTimestamp.Should().NotBeNull();
            (transaction.EndTimestamp - transaction.StartTimestamp).Should().BeGreaterOrEqualTo(TimeSpan.Zero);
        }
Example #9
0
        public void StartChild_SamplingInherited_False()
        {
            // Arrange
            var transaction = new TransactionTracer(DisabledHub.Instance, "my name", "my op")
            {
                IsSampled = false
            };

            // Act
            var child = transaction.StartChild("child op", "child desc");

            // Assert
            child.IsSampled.Should().BeFalse();
        }
Example #10
0
        public void StartChild_LevelOne_Works()
        {
            // Arrange
            var transaction = new TransactionTracer(DisabledHub.Instance, "my name", "my op");

            // Act
            var child = transaction.StartChild("child op", "child desc");

            // Assert
            transaction.Spans.Should().HaveCount(1);
            transaction.Spans.Should().Contain(child);
            child.Operation.Should().Be("child op");
            child.Description.Should().Be("child desc");
            child.ParentSpanId.Should().Be(transaction.SpanId);
        }
Example #11
0
        public void Finish_StatusSet_DoesNotOverride()
        {
            // Arrange
            var hub         = Substitute.For <IHub>();
            var transaction = new TransactionTracer(hub, "my name", "my op")
            {
                Status = SpanStatus.DataLoss
            };

            // Act
            transaction.Finish();

            // Assert
            transaction.Status.Should().Be(SpanStatus.DataLoss);
        }
        public void Finish_CapturesTransaction()
        {
            // Arrange
            var client = Substitute.For <ISentryClient>();
            var hub    = new Hub(client, new SentryOptions {
                Dsn = DsnSamples.ValidDsnWithoutSecret
            });

            var transaction = new TransactionTracer(hub, "my name", "my op");

            // Act
            transaction.Finish();

            // Assert
            client.Received(1).CaptureTransaction(Arg.Any <Transaction>());
        }
Example #13
0
        public void StartChild_TraceIdInherited()
        {
            // Arrange
            var transaction = new TransactionTracer(DisabledHub.Instance, "my name", "my op");

            // Act
            var children = new[]
            {
                transaction.StartChild("op1"),
                transaction.StartChild("op2"),
                transaction.StartChild("op3")
            };

            // Assert
            children.Should().OnlyContain(s => s.TraceId == transaction.TraceId);
        }
Example #14
0
        public void StartChild_Limit_Maintained()
        {
            // Arrange
            var transaction = new TransactionTracer(DisabledHub.Instance, "my name", "my op")
            {
                IsSampled = true
            };

            // Act
            var spans = Enumerable
                        .Range(0, 1000 * 2)
                        .Select(i => transaction.StartChild("span " + i))
                        .ToArray();

            // Assert
            transaction.Spans.Should().HaveCount(1000);
            spans.Count(s => s.IsSampled == true).Should().Be(1000);
        }
Example #15
0
        /// <summary>
        /// Create a Tracers subsystem with the desired implementation, if it can be found and created.
        ///
        /// Otherwise the default implementation is used, and a warning is logged to the given StringLogger. </summary>
        /// <param name="desiredImplementationName"> The name of the desired {@link org.neo4j.kernel.monitoring.tracing
        /// .TracerFactory} implementation, as given by its <seealso cref="TracerFactory.getImplementationName()"/> method. </param>
        /// <param name="msgLog"> A <seealso cref="Log"/> for logging when the desired implementation cannot be created. </param>
        /// <param name="monitors"> the monitoring manager </param>
        /// <param name="jobScheduler"> a scheduler for async jobs </param>
        public Tracers(string desiredImplementationName, Log msgLog, Monitors monitors, JobScheduler jobScheduler, SystemNanoClock clock)
        {
            if ("null".Equals(desiredImplementationName, StringComparison.OrdinalIgnoreCase))
            {
                PageCursorTracerSupplier = DefaultPageCursorTracerSupplier.NULL;
                PageCacheTracer          = PageCacheTracer.NULL;
                TransactionTracer        = Org.Neo4j.Kernel.impl.transaction.tracing.TransactionTracer_Fields.Null;
                CheckPointTracer         = Org.Neo4j.Kernel.impl.transaction.tracing.CheckPointTracer_Fields.Null;
                LockTracer = LockTracer.NONE;
            }
            else
            {
                TracerFactory foundFactory = new DefaultTracerFactory();
                bool          found        = string.ReferenceEquals(desiredImplementationName, null);
                foreach (TracerFactory factory in Service.load(typeof(TracerFactory)))
                {
                    try
                    {
                        if (factory.ImplementationName.Equals(desiredImplementationName, StringComparison.OrdinalIgnoreCase))
                        {
                            foundFactory = factory;
                            found        = true;
                            break;
                        }
                    }
                    catch (Exception e)
                    {
                        msgLog.Warn("Failed to instantiate desired tracer implementations '" + desiredImplementationName + "'", e);
                    }
                }

                if (!found)
                {
                    msgLog.Warn("Using default tracer implementations instead of '%s'", desiredImplementationName);
                }

                PageCursorTracerSupplier = foundFactory.CreatePageCursorTracerSupplier(monitors, jobScheduler);
                PageCacheTracer          = foundFactory.CreatePageCacheTracer(monitors, jobScheduler, clock, msgLog);
                TransactionTracer        = foundFactory.CreateTransactionTracer(monitors, jobScheduler);
                CheckPointTracer         = foundFactory.CreateCheckPointTracer(monitors, jobScheduler);
                LockTracer = foundFactory.CreateLockTracer(monitors, jobScheduler);
            }
        }
Example #16
0
    public void Finish_UnfinishedSpansGetsFinishedWithDeadlineStatus()
    {
        // Arrange
        var transaction = new TransactionTracer(DisabledHub.Instance, "my name", "my op");

        transaction.StartChild("children1");
        transaction.StartChild("children2");
        transaction.StartChild("children3.finished").Finish(SpanStatus.Ok);
        transaction.StartChild("children4");

        // Act
        transaction.Finish();

        // Assert

        Assert.All(transaction.Spans.Where(span => !span.Operation.EndsWith("finished")), span =>
        {
            Assert.True(span.IsFinished);
            Assert.Equal(SpanStatus.DeadlineExceeded, span.Status);
        });
        Assert.Single(transaction.Spans.Where(span => span.Operation.EndsWith("finished") && span.Status == SpanStatus.Ok));
    }
        public Fixture()
        {
            Logger = new InMemoryDiagnosticLogger();

            Options = new SentryOptions
            {
                Debug            = true,
                DiagnosticLogger = Logger,
                DiagnosticLevel  = SentryLevel.Debug,
                TracesSampleRate = 1,
            };
            Tracer = new TransactionTracer(Hub, "foo", "bar")
            {
                IsSampled = true
            };
            _scope = new Scope
            {
                Transaction = Tracer
            };
            Hub = Substitute.For <IHub>();
            Hub.When(hub => hub.ConfigureScope(Arg.Any <Action <Scope> >()))
            .Do(callback => callback.Arg <Action <Scope> >().Invoke(_scope));
        }
Example #18
0
        public void SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject()
        {
            // Arrange
            var timestamp = DateTimeOffset.MaxValue;
            var context   = new TransactionContext(
                SpanId.Create(),
                SpanId.Create(),
                SentryId.Create(),
                "name123",
                "op123",
                "desc",
                SpanStatus.AlreadyExists,
                null, // sampling isn't serialized and getting FluentAssertions
                      // to ignore that on Spans and contexts isn't really straight forward
                true);

            var transaction = new TransactionTracer(DisabledHub.Instance, context)
            {
                Description = "desc123",
                Status      = SpanStatus.Aborted,
                User        = new User {
                    Id = "user-id"
                },
                Request = new Request {
                    Method = "POST"
                },
                Sdk = new SdkVersion {
                    Name = "SDK-test", Version = "1.1.1"
                },
                Environment = "environment",
                Level       = SentryLevel.Fatal,
                Contexts    =
                {
                    ["context_key"]    = "context_value",
                    [".NET Framework"] = new Dictionary <string, string>
                    {
                        [".NET Framework"]        = "\"v2.0.50727\", \"v3.0\", \"v3.5\"",
                        [".NET Framework Client"] = "\"v4.8\", \"v4.0.0.0\"",
                        [".NET Framework Full"]   = "\"v4.8\""
                    }
                },
            };

            // Don't overwrite the contexts object as it contains trace data.
            // See https://github.com/getsentry/sentry-dotnet/issues/752

            transaction.Sdk.AddPackage(new Package("name", "version"));
            transaction.AddBreadcrumb(new Breadcrumb(timestamp, "crumb"));
            transaction.AddBreadcrumb(new Breadcrumb(
                                          timestamp,
                                          "message",
                                          "type",
                                          new Dictionary <string, string> {
                { "data-key", "data-value" }
            },
                                          "category",
                                          BreadcrumbLevel.Warning)
                                      );

            transaction.SetExtra("extra_key", "extra_value");
            transaction.Fingerprint = new[] { "fingerprint" };
            transaction.SetTag("tag_key", "tag_value");

            var child1 = transaction.StartChild("child_op123", "child_desc123");

            child1.Status = SpanStatus.Unimplemented;
            child1.SetTag("q", "v");
            child1.SetExtra("f", "p");
            child1.Finish(SpanStatus.Unimplemented);

            var child2 = transaction.StartChild("child_op999", "child_desc999");

            child2.Status = SpanStatus.OutOfRange;
            child2.SetTag("xxx", "zzz");
            child2.SetExtra("f222", "p111");
            child2.Finish(SpanStatus.OutOfRange);

            transaction.Finish(SpanStatus.Aborted);

            // Act
            var finalTransaction = new Transaction(transaction);
            var actualString     = finalTransaction.ToJsonString();
            var actual           = Transaction.FromJson(Json.Parse(actualString));

            // Assert
            actual.Should().BeEquivalentTo(finalTransaction, o =>
            {
                // Timestamps lose some precision when writing to JSON
                o.Using <DateTimeOffset>(ctx =>
                                         ctx.Subject.Should().BeCloseTo(ctx.Expectation, TimeSpan.FromMilliseconds(1))
                                         ).WhenTypeIs <DateTimeOffset>();

                return(o);
            });
        }