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)); }
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 }
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>()); }
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); }
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") ) ); }
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); }
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); }
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); }
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(); }
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); }
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>()); }
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); }
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); }
/// <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); } }
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)); }
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); }); }