ReportOnFailureLibrary 0.1.2
dotnet add package ReportOnFailureLibrary --version 0.1.2
NuGet\Install-Package ReportOnFailureLibrary -Version 0.1.2
<PackageReference Include="ReportOnFailureLibrary" Version="0.1.2" />
<PackageVersion Include="ReportOnFailureLibrary" Version="0.1.2" />
<PackageReference Include="ReportOnFailureLibrary" />
paket add ReportOnFailureLibrary --version 0.1.2
#r "nuget: ReportOnFailureLibrary, 0.1.2"
#:package ReportOnFailureLibrary@0.1.2
#addin nuget:?package=ReportOnFailureLibrary&version=0.1.2
#tool nuget:?package=ReportOnFailureLibrary&version=0.1.2
Report On Failure Library (ROFL)
A .NET library for collecting and outputting contextual information when tests or operations fail. Designed to help with debugging by automatically gathering relevant data from databases, APIs, and other sources when something goes wrong.
Purpose
ROFL helps developers and testers gather debugging information automatically when failures occur on E2E and integration tests. Instead of manually collecting logs, database states, or API responses after a failure, this library allows you to pre-configure data collection that executes only when needed.
Common use cases:
- Capturing database state when integration tests fail
- Collecting API responses for debugging failed service calls
- Gathering configuration data when deployment verification fails
- Saving system metrics when performance tests don't meet thresholds
Installation
dotnet package add ReportOnFailureLibrary
Usage
- Create a registry in your E2E or integration test. Configure the output location.
- Add reporters that are relevant to the test as a whole.
- Add reporters that are relevant for the next part of the test.
- When part of the test passes, remove any reporters you no longer care about and add new ones for upcoming parts of the Test.
- If the test fails, call the registry to execute in the teardown.
Quick Start
using ReportOnFailure;
using ReportOnFailure.Reporters;
using ReportOnFailure.Enums;
// Set up the registry
var registry = new Registry()
.WithDestinationLocation(@"C:\FailureReports")
.WithCompression()
.WithExecutionMode(ExecutionMode.Asynchronous);
// Add a database reporter
var dbReporter = new DbReporter()
.WithDatabaseType(DatabaseType.SqlServer)
.WithConnectionString("Server=localhost;Database=TestDb;Trusted_Connection=true;")
.WithQuery("SELECT TOP 10 * FROM Users ORDER BY CreatedDate DESC")
.WithResultsFormat(ResultsFormat.Json)
.WithFileNamePrefix("UserState");
registry.RegisterReporter(dbReporter);
// Add an API reporter
var apiReporter = new ApiReporter()
.WithBaseUrl("https://api.myservice.com")
.WithEndpoint("/health")
.WithMethod(HttpMethod.GET)
.WithBearerToken("your-api-token")
.WithResultsFormat(ResultsFormat.Json)
.WithFileNamePrefix("ServiceHealth");
registry.RegisterReporter(apiReporter);
// Execute when failure occurs
try
{
// Your test or operation that might fail
await SomeOperationThatMightFail();
}
catch (Exception)
{
// Collect failure context
await registry.ExecuteAsync();
throw; // Re-throw the original exception
}
//Test passed? Remove the reporters, add ones for the next assert
registry.UnregisterReporter(apiReporter);
registry.UnregisterReporter(dbReporter);
Setting Up the Registry
The Registry
is the main orchestrator that manages reporters and handles output configuration.
Basic Setup
var registry = new Registry();
Configuration Options
Destination Location
Set where reports will be written:
registry.WithDestinationLocation(@"C:\Reports"); // Local folder
registry.WithDestinationLocation(@"\\server\share\logs"); // Network share
Compression
Enable compression to reduce file sizes:
registry.WithCompression(); // Creates .zip files instead of loose files
Execution Mode
Control how reporters are executed:
registry.WithExecutionMode(ExecutionMode.Synchronous); // Default: one after another
registry.WithExecutionMode(ExecutionMode.Asynchronous); // Parallel execution
Destination Type
Currently supports file system output:
registry.WithDestinationType(DestinationType.FileSystem); // Default
// Future: AzureBlobStorage, AmazonS3, GoogleCloudStorage
Fluent Configuration
Chain configuration methods together:
var registry = new Registry()
.WithDestinationLocation(@"C:\FailureReports")
.WithCompression()
.WithExecutionMode(ExecutionMode.Asynchronous);
Adding Reporters
Reporters define what data to collect and how to format it. Each reporter focuses on a specific data source.
Database Reporter
Collect data from SQL databases:
var dbReporter = new DbReporter()
.WithDatabaseType(DatabaseType.SqlServer)
.WithConnectionString("your-connection-string")
.WithQuery("SELECT * FROM ErrorLogs WHERE CreatedDate > @Since")
.WithCommandTimeout(60)
.AddParameter(new SqlParameter("@Since", DateTime.Now.AddHours(-1)))
.WithResultsFormat(ResultsFormat.Json)
.WithFileNamePrefix("ErrorLogs");
registry.RegisterReporter(dbReporter);
Supported databases:
DatabaseType.SqlServer
DatabaseType.Sqlite
DatabaseType.Odbc
Result formats:
ResultsFormat.Json
- Structured JSON outputResultsFormat.Csv
- Comma-separated valuesResultsFormat.Text
- Human-readable textResultsFormat.Xml
- XML format (planned)ResultsFormat.Html
- HTML format (planned)
API Reporter
Collect data from REST APIs:
var restApiReporter = new restApiReporter()
.WithBaseUrl("https://api.example.com")
.WithEndpoint("/v1/status")
.WithMethod(HttpMethod.GET)
.WithHeader("Accept", "application/json")
.WithQueryParameter("detailed", "true")
.WithBearerToken("your-jwt-token")
.WithTimeout(30)
.WithResultsFormat(ResultsFormat.Json)
.WithFileNamePrefix("ApiStatus");
registry.RegisterReporter(restApiReporter);
Authentication options:
// Bearer token
.WithBearerToken("your-jwt-token")
// Basic authentication
.WithBasicAuth("username", "password")
// API key in header
.WithApiKey("X-API-Key", "your-api-key", inHeader: true)
// API key in query string
.WithApiKey("api_key", "your-api-key", inHeader: false)
// OAuth2 client credentials (automatic token management)
.WithOAuth2ClientCredentials(
tokenEndpoint: "https://auth.example.com/oauth/token",
clientId: "your-client-id",
clientSecret: "your-client-secret",
scope: "read:data")
Multiple Reporters
Register multiple reporters to collect different types of data:
// Database state
registry.RegisterReporter(userStateReporter);
registry.RegisterReporter(orderHistoryReporter);
// API health checks
registry.RegisterReporter(authServiceReporter);
registry.RegisterReporter(paymentServiceReporter);
// Configuration data
registry.RegisterReporter(appConfigReporter);
Unregister Reporters
// Database state
registry.UnregisterReporter(userStateReporter);
Reporter-Specific Settings
Override global settings per reporter:
var urgentReporter = new DbReporter()
.WithQuery("SELECT * FROM CriticalErrors")
.WithExecutionModeOverride(ExecutionMode.Synchronous) // Force sync even if registry is async
.WithResultsFormat(ResultsFormat.Json);
Triggering Report Generation
Synchronous Execution
try
{
// Your operation
PerformOperation();
}
catch (Exception)
{
registry.Execute(); // Blocks until all reports are generated
throw;
}
Asynchronous Execution (Recommended)
try
{
await PerformOperationAsync();
}
catch (Exception)
{
await registry.ExecuteAsync(); // Non-blocking, better performance
throw;
}
With Cancellation
using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
try
{
await PerformOperationAsync();
}
catch (Exception)
{
await registry.ExecuteAsync(cts.Token); // Respect cancellation
throw;
}
Output Format
Reports are saved with descriptive filenames:
{FileNamePrefix}_{timestamp}_{guid}.{extension}
Examples:
UserState_20241208_143052_a1b2c3d4.json
ApiHealth_20241208_143053_e5f6g7h8.csv
ErrorLogs_20241208_143054_i9j0k1l2.txt
With compression enabled:
UserState_20241208_143052_a1b2c3d4.zip
(contains .json file inside)
Integration Examples
xUnit Test Integration
public class IntegrationTests : IAsyncLifetime
{
private readonly Registry _failureReporter;
public IntegrationTests()
{
_failureReporter = new Registry()
.WithDestinationLocation(@"C:\TestFailures")
.WithExecutionMode(ExecutionMode.Asynchronous);
// Add relevant reporters
_failureReporter.RegisterReporter(CreateDatabaseReporter());
_failureReporter.RegisterReporter(CreateApiReporter());
}
[Fact]
public async Task UserRegistration_ShouldCreateUser()
{
try
{
// Test logic here
var result = await _userService.RegisterAsync(newUser);
Assert.NotNull(result.UserId);
}
catch (Exception)
{
await _failureReporter.ExecuteAsync();
throw;
}
}
}
ASP.NET Core Integration
public class HealthCheckService
{
private readonly Registry _failureReporter;
public HealthCheckService()
{
_failureReporter = new Registry()
.WithDestinationLocation(@"C:\HealthCheckFailures")
.WithCompression();
// Add health check reporters
_failureReporter.RegisterReporter(CreateDatabaseHealthReporter());
_failureReporter.RegisterReporter(CreateExternalServiceReporter());
}
public async Task<HealthCheckResult> CheckSystemHealthAsync()
{
try
{
// Perform health checks
return await PerformHealthChecksAsync();
}
catch (Exception ex)
{
await _failureReporter.ExecuteAsync();
return HealthCheckResult.Unhealthy(ex.Message);
}
}
}
Advanced Configuration
Custom File Naming
var reporter = new DbReporter()
.WithFileNamePrefix("CriticalUserData")
.WithQuery("SELECT * FROM Users WHERE Status = 'Critical'");
// Generates: CriticalUserData_20241208_143052_a1b2c3d4.json
Execution Mode Mixing
var registry = new Registry()
.WithExecutionMode(ExecutionMode.Asynchronous); // Default for all reporters
// But override for specific reporters
var criticalReporter = new DbReporter()
.WithExecutionModeOverride(ExecutionMode.Synchronous) // Force sync for this one
.WithQuery("SELECT * FROM CriticalTable");
var normalReporter = new ApiReporter()
.WithBaseUrl("https://api.example.com")
.WithEndpoint("/status");
// Uses async mode from registry
registry.RegisterReporter(criticalReporter);
registry.RegisterReporter(normalReporter);
await registry.ExecuteAsync();
// criticalReporter runs synchronously, normalReporter runs async
Best Practices
Configure Once: Set up the registry and reporters during application startup or test initialization.
Use Meaningful Prefixes: Choose
FileNamePrefix
values that clearly identify the data being collected.Limit Data Volume: Use appropriate WHERE clauses and LIMIT/TOP statements to avoid collecting excessive data.
Handle Sensitive Data: Be careful not to collect passwords, API keys, or other sensitive information in your queries.
Use Compression: Enable compression for production use to reduce storage requirements.
Set Appropriate Timeouts: Configure reasonable timeouts for database queries and API calls.
Async When Possible: Use
ExecuteAsync()
for better performance, especially when collecting from multiple sources.
Error Handling
The library handles common errors gracefully:
- Database connection failures: Logged but don't prevent other reporters from running
- API timeouts: Configurable timeouts with proper error reporting
- File system issues: Directory creation and permission handling
- Invalid queries: SQL errors are captured in the output
Failed reports generate error files with diagnostic information rather than throwing exceptions that could mask the original failure.
Requirements
- .NET 8.0 or .NET 9.0
License
MIT License
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Data.SqlClient (>= 6.0.2)
- Microsoft.Data.Sqlite (>= 9.0.7)
- System.Data.Odbc (>= 9.0.7)
-
net9.0
- Microsoft.Data.SqlClient (>= 6.0.2)
- Microsoft.Data.Sqlite (>= 9.0.7)
- System.Data.Odbc (>= 9.0.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.