public async Task DefaultWithRequestBodyNoError(string formName, bool useOnlyDiagnosticSource) { CreateAgent(useOnlyDiagnosticSource); var nvc = new List <KeyValuePair <string, string> > { new KeyValuePair <string, string>("Input1", "test1"), new KeyValuePair <string, string>(formName, "test2") }; var req = new HttpRequestMessage(HttpMethod.Post, "api/Home/Post") { Content = new FormUrlEncodedContent(nvc) }; var res = await _client.SendAsync(req); res.IsSuccessStatusCode.Should().BeTrue(); _capturedPayload.WaitForTransactions(); _capturedPayload.Transactions.Should().ContainSingle(); _capturedPayload.WaitForErrors(TimeSpan.FromSeconds(1)); _capturedPayload.Errors.Should().BeNullOrEmpty(); _capturedPayload.FirstTransaction.Context.Request.Body.Should().Be($"Input1=test1&{formName}=[REDACTED]"); }
public async Task CaptureErrorLogsAsApmError() { var payloadSender = new MockPayloadSender(); using var hostBuilder = CreateHostBuilder(payloadSender).Build(); await hostBuilder.StartAsync(); payloadSender.WaitForErrors(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.FirstError.Log.Message.Should().Be("This is a sample error log message, with a sample value: 42"); payloadSender.FirstError.Log.ParamMessage.Should().Be("This is a sample error log message, with a sample value: {intParam}"); // Test a log with exception var logger = (ILogger)hostBuilder.Services.GetService(typeof(ILogger <object>)); try { throw new Exception(); } catch (Exception e) { logger.LogError(e, "error log with exception"); } payloadSender.WaitForErrors(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.Errors.Where(n => n.Log.Message == "error log with exception" && n.Log.StackTrace != null && n.Log.StackTrace.Count > 0) .Should() .NotBeNullOrEmpty(); await hostBuilder.StopAsync(); }
public async Task HomeIndexTransactionWithToggleRecording(bool withDiagnosticSourceOnly) { _agent = new ApmAgent(new TestAgentComponents( _logger, new MockConfigSnapshot(recording: "false"), _capturedPayload)); _client = Helper.ConfigureHttpClient(true, withDiagnosticSourceOnly, _agent, _factory); var response = await _client.GetAsync("/Home/Index"); response.IsSuccessStatusCode.Should().BeTrue(); _capturedPayload.WaitForAny(TimeSpan.FromSeconds(5)); _capturedPayload.Transactions.Should().BeNullOrEmpty(); _capturedPayload.Spans.Should().BeNullOrEmpty(); _capturedPayload.Errors.Should().BeNullOrEmpty(); //flip recording to true _agent.ConfigStore.CurrentSnapshot = new MockConfigSnapshot(recording: "true"); response = await _client.GetAsync("/Home/Index"); response.IsSuccessStatusCode.Should().BeTrue(); _capturedPayload.WaitForTransactions(); _capturedPayload.Transactions.Should().NotBeEmpty(); _capturedPayload.WaitForSpans(); _capturedPayload.Spans.Should().NotBeEmpty(); _capturedPayload.WaitForErrors(TimeSpan.FromSeconds(5)); _capturedPayload.Errors.Should().BeNullOrEmpty(); }
/// <summary> /// Asserts on 1 transaction with 1 span and 1 error /// </summary> private void AssertWith1TransactionAnd1SpanAnd1Error(Action <ITransaction> action) { var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { agent.Tracer.CaptureTransaction(TransactionName, TransactionType, t => { WaitHelpers.SleepMinimum(); action(t); }); } payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().NotBeEmpty(); payloadSender.FirstTransaction.Name.Should().Be(TransactionName); payloadSender.FirstTransaction.Type.Should().Be(TransactionType); var duration = payloadSender.FirstTransaction.Duration; duration.Should().BeGreaterOrEqualToMinimumSleepLength(3); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction.Should().NotBeEmpty(); payloadSender.SpansOnFirstTransaction[0].Name.Should().Be(SpanName); payloadSender.SpansOnFirstTransaction[0].Type.Should().Be(SpanType); payloadSender.WaitForErrors(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.FirstError.Exception.Type.Should().Be(typeof(InvalidOperationException).FullName); payloadSender.FirstError.Exception.Message.Should().Be(ExceptionMessage); }
/// <summary> /// Asserts on 1 transaction with 1 async span and 1 error /// </summary> private async Task <MockPayloadSender> AssertWith1TransactionAnd1ErrorAnd1SpanAsync(Func <ITransaction, Task> func) { var payloadSender = new MockPayloadSender(); var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender)); await agent.Tracer.CaptureTransaction(TransactionName, TransactionType, async t => { await WaitHelpers.DelayMinimum(); await func(t); }); payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().NotBeEmpty(); payloadSender.FirstTransaction.Name.Should().Be(TransactionName); payloadSender.FirstTransaction.Type.Should().Be(TransactionType); var duration = payloadSender.FirstTransaction.Duration; duration.Should().BeGreaterOrEqualToMinimumSleepLength(3); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction.Should().NotBeEmpty(); payloadSender.SpansOnFirstTransaction[0].Name.Should().Be(SpanName); payloadSender.SpansOnFirstTransaction[0].Type.Should().Be(SpanType); payloadSender.WaitForErrors(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.FirstError.Exception.Type.Should().Be(typeof(InvalidOperationException).FullName); payloadSender.FirstError.Exception.Message.Should().Be(ExceptionMessage); return(payloadSender); }
public void ErrorOnSpan() { const string transactionName = TestTransaction; const string transactionType = UnitTest; const string spanName = "TestSpan"; const string exceptionMessage = "Foo!"; var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { var transaction = agent.Tracer.StartTransaction(transactionName, transactionType); var span = transaction.StartSpan(spanName, ApiConstants.TypeExternal); Thread.Sleep(5); //Make sure we have duration > 0 try { throw new InvalidOperationException(exceptionMessage); } catch (Exception e) { span.CaptureException(e); } span.End(); transaction.End(); } payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().ContainSingle(); payloadSender.WaitForErrors(); payloadSender.Errors.Should().ContainSingle(); payloadSender.FirstError.Exception.Message.Should().Be(exceptionMessage); }
public void Includes_Cause_When_Exception_Has_InnerException() { var mockPayloadSender = new MockPayloadSender(); using var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender)); agent.Tracer.CaptureTransaction("Test", "Test", t => { var exception = new Exception( "Outer exception", new Exception("Inner exception", new Exception("Inner inner exception"))); t.CaptureException(exception); }); mockPayloadSender.WaitForErrors(); var error = mockPayloadSender.FirstError; error.Should().NotBeNull(); var capturedException = error.Exception; capturedException.Should().NotBeNull(); capturedException.Message.Should().Be("Outer exception"); capturedException.Cause.Should().NotBeNull().And.HaveCount(2); var firstCause = capturedException.Cause[0]; firstCause.Message.Should().Be("Inner exception"); firstCause.Type.Should().Be("System.Exception"); var secondCause = capturedException.Cause[1]; secondCause.Message.Should().Be("Inner inner exception"); secondCause.Type.Should().Be("System.Exception"); }
public void ErrorOnTransactionWithEmptyHeaders() { var mockPayloadSender = new MockPayloadSender(); using var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender)); agent.Tracer.CaptureTransaction("Test", "Test", t => { t.Context.Request = new Request("GET", new Url { Full = "http://localhost" }); t.Context.Response = new Response(); t.CaptureError("Test Error", "Test", new StackTrace().GetFrames()); }); mockPayloadSender.WaitForErrors(); mockPayloadSender.FirstError.Should().NotBeNull(); mockPayloadSender.FirstError.Context.Should().NotBeNull(); mockPayloadSender.FirstError.Context.Request.Should().NotBeNull(); mockPayloadSender.FirstError.Context.Request.Headers.Should().BeNull(); mockPayloadSender.FirstError.Context.Response.Should().NotBeNull(); mockPayloadSender.FirstError.Context.Response.Headers.Should().BeNull(); mockPayloadSender.FirstError.Context.InternalLabels.Value.InnerDictionary.Should().BeEmpty(); }
public async Task SanitizeHeadersOnError(string headerName, bool useOnlyDiagnosticSource) { CreateAgent(useOnlyDiagnosticSource); _client.DefaultRequestHeaders.Add(headerName, "123"); await _client.GetAsync("/Home/TriggerError"); _capturedPayload.WaitForTransactions(); _capturedPayload.Transactions.Should().ContainSingle(); _capturedPayload.FirstTransaction.Context.Should().NotBeNull(); _capturedPayload.FirstTransaction.Context.Request.Should().NotBeNull(); _capturedPayload.FirstTransaction.Context.Request.Headers.Should().NotBeNull(); _capturedPayload.FirstTransaction.Context.Request.Headers[headerName].Should().Be("[REDACTED]"); _capturedPayload.WaitForErrors(); _capturedPayload.Errors.Should().ContainSingle(); _capturedPayload.FirstError.Context.Should().NotBeNull(); _capturedPayload.FirstError.Context.Request.Should().NotBeNull(); _capturedPayload.FirstError.Context.Request.Headers.Should().NotBeNull(); _capturedPayload.FirstError.Context.Request.Headers[headerName].Should().Be("[REDACTED]"); }
/// <summary> /// Asserts on 1 transaction with 1 span and 1 error /// </summary> private void AssertWith1TransactionAnd1SpanAnd1ErrorOnSubSpan(Action <ISpan> action) { var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { WaitHelpers.SleepMinimum(); agent.Tracer.CaptureTransaction(TransactionName, TransactionType, t => { WaitHelpers.SleepMinimum(); t.CaptureSpan("aa", "bb", s => { WaitHelpers.SleepMinimum(); action(s); }); }); } payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().NotBeEmpty(); payloadSender.FirstTransaction.Name.Should().Be(TransactionName); payloadSender.FirstTransaction.Type.Should().Be(TransactionType); var duration = payloadSender.FirstTransaction.Duration; duration.Should().BeGreaterOrEqualToMinimumSleepLength(3); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction.Should().NotBeEmpty(); payloadSender.SpansOnFirstTransaction[0].Name.Should().Be(SpanName); payloadSender.SpansOnFirstTransaction[0].Type.Should().Be(SpanType); payloadSender.WaitForErrors(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.FirstError.Exception.Type.Should().Be(typeof(InvalidOperationException).FullName); payloadSender.FirstError.Exception.Message.Should().Be(ExceptionMessage); var orderedSpans = payloadSender.Spans.OrderBy(n => n.Timestamp).ToList(); var firstSpan = orderedSpans.First(); var innerSpan = orderedSpans.Last(); firstSpan.ParentId.Should().Be(payloadSender.FirstTransaction.Id); innerSpan.ParentId.Should().Be(firstSpan.Id); firstSpan.TransactionId.Should().Be(payloadSender.FirstTransaction.Id); innerSpan.TransactionId.Should().Be(payloadSender.FirstTransaction.Id); }
private async Task <MockPayloadSender> AssertWith1TransactionAnd1ErrorAnd1SpanAsyncOnSubSpan(Func <ISpan, Task> func) { var payloadSender = new MockPayloadSender(); using var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender)); await agent.Tracer.CaptureTransaction(TransactionName, TransactionType, async t => { await WaitHelpers.DelayMinimum(); await t.CaptureSpan("TestSpan", "TestSpanType", async s => { await WaitHelpers.DelayMinimum(); await func(s); }); }); payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().NotBeEmpty(); payloadSender.FirstTransaction.Name.Should().Be(TransactionName); payloadSender.FirstTransaction.Type.Should().Be(TransactionType); var duration = payloadSender.FirstTransaction.Duration; duration.Should().BeGreaterOrEqualToMinimumSleepLength(3); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction.Should().NotBeEmpty(); payloadSender.SpansOnFirstTransaction[0].Name.Should().Be(SpanName); payloadSender.SpansOnFirstTransaction[0].Type.Should().Be(SpanType); payloadSender.WaitForErrors(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.FirstError.Exception.Type.Should().Be(typeof(InvalidOperationException).FullName); payloadSender.FirstError.Exception.Message.Should().Be(ExceptionMessage); var orderedSpans = payloadSender.Spans.OrderBy(n => n.Timestamp).ToList(); var firstSpan = orderedSpans.First(); var innerSpan = orderedSpans.Last(); firstSpan.ParentId.Should().Be(payloadSender.FirstTransaction.Id); innerSpan.ParentId.Should().Be(firstSpan.Id); firstSpan.TransactionId.Should().Be(payloadSender.FirstTransaction.Id); innerSpan.TransactionId.Should().Be(payloadSender.FirstTransaction.Id); return(payloadSender); }
public async Task CaptureErrorLogsAsApmError() { var payloadSender = new MockPayloadSender(); using var hostBuilder = CreateHostBuilder(payloadSender).Build(); await hostBuilder.StartAsync(); payloadSender.WaitForErrors(); payloadSender.Errors.Should().NotBeEmpty(); payloadSender.FirstError.Log.Message.Should().Be("This is a sample error log message, with a sample value: 42"); payloadSender.FirstError.Log.ParamMessage.Should().Be("This is a sample error log message, with a sample value: {intParam}"); await hostBuilder.StopAsync(); }
public void LabelsOnTransactionAndSpan() { const string transactionName = TestTransaction; const string transactionType = UnitTest; const string spanName = "TestSpan"; const string exceptionMessage = "Foo!"; var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { var transaction = agent.Tracer.StartTransaction(transactionName, transactionType); transaction.SetLabel("fooTransaction1", "barTransaction1"); transaction.SetLabel("fooTransaction2", "barTransaction2"); var span = transaction.StartSpan(spanName, ApiConstants.TypeExternal); span.SetLabel("fooSpan1", "barSpan1"); span.SetLabel("fooSpan2", "barSpan2"); Thread.Sleep(5); //Make sure we have duration > 0 try { throw new InvalidOperationException(exceptionMessage); } catch (Exception e) { span.CaptureException(e); } span.End(); transaction.End(); } payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().ContainSingle(); payloadSender.WaitForErrors(); payloadSender.Errors.Should().ContainSingle(); payloadSender.FirstError.Exception.Message.Should().Be(exceptionMessage); payloadSender.FirstTransaction.Context.InternalLabels.Value.MergedDictionary["fooTransaction1"].Value.Should().Be("barTransaction1"); payloadSender.FirstTransaction.Context.InternalLabels.Value.MergedDictionary["fooTransaction2"].Value.Should().Be("barTransaction2"); payloadSender.WaitForSpans(); payloadSender.SpansOnFirstTransaction[0].Context.InternalLabels.Value.MergedDictionary["fooSpan1"].Value.Should().Be("barSpan1"); payloadSender.SpansOnFirstTransaction[0].Context.InternalLabels.Value.MergedDictionary["fooSpan2"].Value.Should().Be("barSpan2"); }
public void ErrorOnEmptyTransaction() { var mockPayloadSender = new MockPayloadSender(); using var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender)); agent.Tracer.CaptureTransaction("Test", "Test", t => { t.CaptureError("Test Error", "Test", new StackTrace().GetFrames()); mockPayloadSender.WaitForErrors(); mockPayloadSender.FirstError.Should().NotBeNull("error should not be null"); mockPayloadSender.FirstError.Context.Should().NotBeNull("error context should not be null"); mockPayloadSender.FirstError.Context.Request.Should().BeNull(); mockPayloadSender.FirstError.Context.Response.Should().BeNull(); }); }
/// <summary> /// Shared between ErrorOnTransaction and ErrorOnTransactionWithCulprit /// </summary> /// <param name="culprit">Culprit.</param> private static void ErrorOnTransactionCommon(string culprit = null) { const string transactionName = TestTransaction; const string transactionType = UnitTest; const string exceptionMessage = "Foo!"; var payloadSender = new MockPayloadSender(); using (var agent = new ApmAgent(new TestAgentComponents(payloadSender: payloadSender))) { var transaction = agent.Tracer.StartTransaction(transactionName, transactionType); Thread.Sleep(5); //Make sure we have duration > 0 try { throw new InvalidOperationException(exceptionMessage); } catch (Exception e) { if (string.IsNullOrEmpty(culprit)) { transaction.CaptureException(e); } else { transaction.CaptureException(e, culprit); } } transaction.End(); } payloadSender.WaitForTransactions(); payloadSender.Transactions.Should().ContainSingle(); payloadSender.WaitForErrors(); payloadSender.Errors.Should().ContainSingle(); payloadSender.FirstError.Exception.Message.Should().Be(exceptionMessage); payloadSender.FirstError.Exception.Message.Should().Be(exceptionMessage); payloadSender.FirstError.Culprit.Should().Be(!string.IsNullOrEmpty(culprit) ? culprit : "Elastic.Apm.Tests.ApiTests.ApiTests"); }
public void ErrorShouldContainTransactionData(bool isSampled, bool captureOnSpan, bool captureAsError) { var payloadSender = new MockPayloadSender(); var expectedErrorContext = new Context(); expectedErrorContext.InternalLabels.Value.InnerDictionary["one"] = 1; expectedErrorContext.InternalLabels.Value.InnerDictionary["twenty two"] = "22"; expectedErrorContext.InternalLabels.Value.InnerDictionary["true"] = true; ITransaction capturedTransaction = null; IExecutionSegment errorCapturingExecutionSegment = null; var mockConfig = new MockConfigSnapshot(transactionSampleRate: isSampled ? "1" : "0"); using (var agent = new ApmAgent(new TestAgentComponents(config: mockConfig, payloadSender: payloadSender))) { agent.Tracer.CaptureTransaction(TestTransaction, CustomTransactionTypeForTests, transaction => { capturedTransaction = transaction; foreach (var item in expectedErrorContext.InternalLabels.Value.MergedDictionary) { transaction.Context.InternalLabels.Value.MergedDictionary[item.Key] = item.Value; } ISpan span = null; if (captureOnSpan) { span = transaction.StartSpan(TestSpan1, ApiConstants.TypeExternal); errorCapturingExecutionSegment = span; } else { errorCapturingExecutionSegment = transaction; } if (captureAsError) { errorCapturingExecutionSegment.CaptureError("Test error message", "Test error culprit", new StackTrace(true).GetFrames()); } else { errorCapturingExecutionSegment.CaptureException(new TestException("test exception")); } // Immutable snapshot of the context should be captured instead of reference to a mutable object // transaction.Context.Labels["three hundred thirty three"] = "333"; span?.End(); }); } payloadSender.WaitForErrors(); payloadSender.Errors.Count.Should().Be(1); payloadSender.FirstError.Transaction.IsSampled.Should().Be(isSampled); payloadSender.FirstError.Transaction.Type.Should().Be(CustomTransactionTypeForTests); payloadSender.FirstError.TransactionId.Should().Be(capturedTransaction.Id); payloadSender.FirstError.TraceId.Should().Be(capturedTransaction.TraceId); payloadSender.FirstError.ParentId.Should() .Be(errorCapturingExecutionSegment.IsSampled ? errorCapturingExecutionSegment.Id : capturedTransaction.Id); payloadSender.FirstError.Transaction.IsSampled.Should().Be(isSampled); if (isSampled) { payloadSender.FirstError.Context.Should().NotBeNull().And.BeEquivalentTo(expectedErrorContext); } else { payloadSender.FirstError.Context.Should().BeNull(); } }
public void ChangeTransactionContextAfterError() { var mockPayloadSender = new MockPayloadSender(); using var agent = new ApmAgent(new TestAgentComponents(payloadSender: mockPayloadSender)); agent.Tracer.CaptureTransaction("Test", "Test", t => { t.Context.Request = new Request("GET", new Url { Full = "http://localhost", Protocol = "http", Search = "abc" }) { Body = "abc", Headers = new Dictionary <string, string> { { "header1", "headerValue" } } }; t.Context.Response = new Response { StatusCode = 404, Finished = false }; t.SetLabel("foo", "bar"); // Let's capture an error t.CaptureError("Test Error", "Test", new StackTrace().GetFrames()); // Let's change CurrentTransaction.Context after the error is captured t.Context.Request.Method = "PUT"; t.Context.Request.Body = "cde"; t.Context.Request.Headers["header2"] = "headerValue"; t.Context.Request.Url.Full = "http://elastic.co"; t.Context.Request.Url.Protocol = "tcp"; t.Context.Request.Url.Search = "cde"; t.Context.Response.StatusCode = 500; t.Context.Response.Finished = true; t.Context.InternalLabels.Value.InnerDictionary["foo"].Value.Should().Be("bar"); // Asserts on the captured error mockPayloadSender.WaitForErrors(); mockPayloadSender.FirstError.Should().NotBeNull("first error should not be null"); mockPayloadSender.FirstError.Context.Should().NotBeNull("context should not be null"); mockPayloadSender.FirstError.Context.Request.Method.Should().Be("GET"); mockPayloadSender.FirstError.Context.Request.Body.Should().Be("abc"); mockPayloadSender.FirstError.Context.Request.Headers.Count.Should().Be(1); mockPayloadSender.FirstError.Context.Request.Headers["header1"].Should().Be("headerValue"); mockPayloadSender.FirstError.Context.Request.Url.Full.Should().Be("http://localhost"); mockPayloadSender.FirstError.Context.Request.Url.Protocol.Should().Be("http"); mockPayloadSender.FirstError.Context.Request.Url.Search.Should().Be("abc"); mockPayloadSender.FirstError.Context.Response.StatusCode.Should().Be(404); mockPayloadSender.FirstError.Context.Response.Finished.Should().BeFalse(); mockPayloadSender.FirstError.Context.InternalLabels.Value.InnerDictionary["foo"].Value.Should().Be("bar"); mockPayloadSender.FirstError.Context.Response.Headers.Should().BeNull(); }); // Asserts on the captured transaction mockPayloadSender.WaitForTransactions(); mockPayloadSender.FirstTransaction.Context.Request.Method.Should().Be("PUT"); mockPayloadSender.FirstTransaction.Context.Request.Body.Should().Be("cde"); mockPayloadSender.FirstTransaction.Context.Request.Headers.Count.Should().Be(2); mockPayloadSender.FirstTransaction.Context.Request.Headers["header1"].Should().Be("headerValue"); mockPayloadSender.FirstTransaction.Context.Request.Headers["header2"].Should().Be("headerValue"); mockPayloadSender.FirstTransaction.Context.Request.Url.Full.Should().Be("http://elastic.co"); mockPayloadSender.FirstTransaction.Context.Request.Url.Protocol.Should().Be("tcp"); mockPayloadSender.FirstTransaction.Context.Request.Url.Search.Should().Be("cde"); mockPayloadSender.FirstTransaction.Context.Response.StatusCode.Should().Be(500); mockPayloadSender.FirstTransaction.Context.Response.Finished.Should().BeTrue(); mockPayloadSender.FirstTransaction.Context.InternalLabels.Value.InnerDictionary["foo"].Value.Should().Be("bar"); mockPayloadSender.FirstTransaction.Context.Response.Headers.Should().BeNull(); }