Appearance
EventLoomer .NET SDK Usage Guide
This guide explains how to use the EventLoomer .NET SDK in your applications. The .NET SDK is our first officially supported SDK, providing seamless integration with .NET's ILogger
infrastructure and direct client access for manual logging. More language-specific SDKs are planned.
While the SDK provides convenience, especially for .NET applications, logs can also be sent directly to our simple HTTP API from any language or platform.
Supported Platforms
The EventLoomer .NET SDK supports:
- .NET 6.0 and later
- ASP.NET Core applications
- Console applications
- Worker services
- Blazor applications (both Server and WebAssembly)
Installation
Install the EventLoomer .NET SDK using NuGet:
bash
dotnet add package EventLoomer.SDK
Configuration
Basic Configuration (Program.cs
/ Startup.cs
)
Configure EventLoomer services using AddEventLoomer
:
csharp
// Example using builder pattern in Program.cs
builder.Services.AddEventLoomer(options =>
{
// Required: Base URL of your EventLoomer API instance
options.BaseUrl = builder.Configuration["EventLoomer:BaseUrl"] ?? "https://api.eventloomer.com";
// Required: Your Team's API Key (find in Team Settings)
options.ApiKey = builder.Configuration["EventLoomer:ApiKey"] ?? throw new InvalidOperationException("ApiKey missing");
// Required for ILogger Integration (Application Logs): Your Project's ID
options.ProjectId = builder.Configuration["EventLoomer:ProjectId"] ?? throw new InvalidOperationException("ProjectId missing for logging");
// Optional: Set the environment (e.g., "Production", "Staging", "Development"). Defaults to "Development".
options.Environment = builder.Configuration["EventLoomer:Environment"] ?? "Development";
// Optional: If true, API call errors won't throw exceptions (check response instead). Defaults to false.
options.FailSilently = true;
// Optional: Enable/disable sending logs via ILogger. Defaults to true.
options.LoggingEnabled = true;
});
Advanced Logger Configuration
You can fine-tune the ILogger
behavior:
csharp
builder.Services.AddEventLoomer(
options => // Standard options from above
{
options.BaseUrl = builder.Configuration["EventLoomer:BaseUrl"];
options.ApiKey = builder.Configuration["EventLoomer:ApiKey"];
options.ProjectId = builder.Configuration["EventLoomer:ProjectId"];
options.Environment = builder.Configuration["EventLoomer:Environment"];
options.LoggingEnabled = true;
},
loggerConfig =>
{
// Configure ILogger specific options
loggerConfig.MinimumLogLevel = LogLevel.Information; // Default: Information
loggerConfig.IncludeScopes = true; // Default: true
loggerConfig.IncludeExceptionStackTrace = true; // Default: true
loggerConfig.UseBatching = true; // Default: true (recommended for performance)
loggerConfig.BatchSize = 50; // Default: 100
loggerConfig.BatchTimeout = TimeSpan.FromSeconds(1); // Default: 2 seconds
loggerConfig.Environment = options.Environment; // Inherits from main options by default
// loggerConfig.CorrelationKey = "your-global-correlation-key"; // Optional global correlation key
});
Usage
The SDK offers two primary ways to send logs:
- Automatic Logging via
ILogger
: Integrates directly with the standard .NET logging framework (Microsoft.Extensions.Logging
). Logs sent this way appear as Application Logs in EventLoomer, associated with the configuredProjectId
. - Manual Logging via
IEventLoomerClient
: Provides direct methods to send logs. You can send logs associated with specific Events/Steps (appearing as Event Logs) or send logs associated with a Project (appearing as Application Logs).
1. Automatic Logging with ILogger (Application Logs)
This is the recommended approach for general application logging within .NET applications. Once configured via AddEventLoomer
, simply inject ILogger<T>
and use standard logging methods. These logs will be automatically sent to EventLoomer and associated with the ProjectId
specified in the options.
csharp
using Microsoft.Extensions.Logging;
public class UserService
{
private readonly ILogger<UserService> _logger;
public UserService(ILogger<UserService> logger)
{
_logger = logger;
}
public async Task RegisterUser(string email, string userId)
{
// Scopes add contextual data to all logs within the 'using' block
using (_logger.BeginScope(new Dictionary<string, object>
{
["UserId"] = userId,
["Operation"] = "UserRegistration"
}))
{
try
{
_logger.LogInformation("Attempting to register user {Email}", email);
// ... registration logic ...
if (await UserExists(email))
{
// LogWarning includes the scope data automatically
_logger.LogWarning("User {Email} already exists.", email);
return;
}
// ... create user ...
_logger.LogInformation("User {Email} registered successfully with ID {UserId}", email, userId);
}
catch (Exception ex)
{
// LogError automatically includes exception details and scope data
_logger.LogError(ex, "Failed to register user {Email}", email);
throw;
}
}
}
private async Task<bool> UserExists(string email) { /* ... check database ... */ return false; }
}
2. Manual Logging with IEventLoomerClient
Inject IEventLoomerClient
for more direct control or when logging specific business events/steps.
a) Sending Event/Step Logs (External Logs):
Use methods like InfoAsync
, ErrorAsync
, etc., or the general SendLogAsync
. These require a uniqueIdentifier
corresponding to an Event or Step you've defined in EventLoomer. These appear as Event Logs in the UI.
csharp
using EventLoomer.SDK;
using EventLoomer.SDK.Models; // For EventLogLevel
public class PaymentService
{
private readonly IEventLoomerClient _eventLoomerClient;
public PaymentService(IEventLoomerClient eventLoomerClient)
{
_eventLoomerClient = eventLoomerClient;
}
public async Task ProcessPayment(PaymentRequest request)
{
string paymentEventId = "payment-processed"; // Unique ID defined in EventLoomer UI
string chargeStepId = "charge-attempted"; // Unique ID defined in EventLoomer UI
await _eventLoomerClient.InfoAsync(paymentEventId, $"Processing payment {request.PaymentId}", request.CorrelationId, request.Environment);
try
{
// ... attempt charge ...
bool success = await _chargeProvider.Charge(request.Amount);
var payload = new { RequestId = request.PaymentId, Success = success, Amount = request.Amount };
await _eventLoomerClient.InfoAsync(chargeStepId, JsonSerializer.Serialize(payload), EventLogLevel.Information, request.CorrelationId, request.Environment);
if(!success) {
await _eventLoomerClient.ErrorAsync(paymentEventId, "Payment failed", request.CorrelationId, request.Environment);
}
}
catch (Exception ex)
{
await _eventLoomerClient.ErrorAsync(paymentEventId, $"Exception during payment: {ex.Message}", request.CorrelationId, request.Environment);
throw;
}
}
}
b) Sending Application Logs Manually:
Use SendApplicationLogAsync
if you need to manually send a log that should be associated with your ProjectId
(like ILogger does). This is less common than using ILogger directly.
csharp
// Example: Logging a background task status manually as an Application Log
await _eventLoomerClient.SendApplicationLogAsync(
projectId: "your-project-id", // Or retrieve from options
categoryName: "BackgroundTasks.Cleanup",
eventId: 1001,
eventName: "CleanupTaskCompleted",
message: $"Cleanup task finished. Removed {count} items.",
level: EventLogLevel.Information,
environment: "Production"
);
Log Levels
Use the appropriate level to indicate severity:
- Trace/Debug: Verbose developer information.
- Information: Standard operational messages.
- Warning: Potential issues or non-critical errors.
- Error: Functional errors that should be investigated.
- Critical: Severe errors indicating system instability.
The SDK uses EventLogLevel
enum for client methods and maps standard Microsoft.Extensions.Logging.LogLevel
for ILogger
.
Correlation Tracking
Pass a correlationKey
(e.g., a request ID, transaction ID, or GUID) consistently across related log calls (both ILogger
scopes and IEventLoomerClient
methods) to link them together in the EventLoomer UI's Flow view.
csharp
public async Task HandleRequest(HttpRequest request)
{
var correlationId = request.Headers["X-Request-ID"].FirstOrDefault() ?? Guid.NewGuid().ToString();
using (_logger.BeginScope(new Dictionary<string, object> { ["CorrelationId"] = correlationId }))
{
_logger.LogInformation("Handling request {Path}", request.Path);
await _someService.DoWorkAsync(correlationId);
await _eventLoomerClient.InfoAsync("REQUEST_END", "Request finished", correlationId);
}
}
Environment Support
Specify the environment (Development
, Staging
, Production
, etc.) to segregate logs.
- Configuration: Set the default environment in
EventLoomerOptions
. - ILogger: Automatically uses the environment from configuration.
- IEventLoomerClient: Pass the
environment
parameter to override the default for specific calls.
csharp
// Set default in Program.cs
options.Environment = "Production";
// Override for a specific manual log
await _eventLoomerClient.WarnAsync(eventId, "Staging specific warning", correlationId, "Staging");
Configuration Validation
You can check if the SDK is configured correctly and can reach the API:
csharp
// Inject IEventLoomerClient client;
// Check status property (updated periodically or after calls)
if (client.ConfigurationStatus != EventLoomerConfigurationStatus.Valid)
{
Console.WriteLine($"Warning: EventLoomer client status: {client.ConfigurationStatus}");
}
// Perform an explicit validation check (makes an API call)
var validationResponse = await client.ValidateConfigurationAsync();
if (!validationResponse.Success)
{
Console.WriteLine($"Error validating EventLoomer config: {validationResponse.Error?.Message}");
// status property will also be updated
} else {
Console.WriteLine($"EventLoomer config status: {validationResponse.Data}");
}
See EventLoomerConfigurationStatus
enum for possible status values.
Error Handling (EventLoomerResponse<T>
)
By default (FailSilently = true
), SDK methods interacting with the API do not throw exceptions for HTTP or API errors. Instead, they return an EventLoomerResponse<string>
(or specific type for ValidateConfigurationAsync
). Always check the Success
property.
csharp
var response = await _eventLoomerClient.InfoAsync("MY_EVENT", "Important data");
if (response.Success)
{
Console.WriteLine($"Log sent successfully. ID (if available): {response.Data}");
}
else
{
// Log failed to send
Console.WriteLine($"Failed to send log: {response.Error?.Code} - {response.Error?.Message}");
// Optionally log response.Error.Details
// Implement fallback logging or retry logic if needed
}
If you set options.FailSilently = false
, API call errors will throw exceptions (typically HttpRequestException
or potentially a custom EventLoomerException
in future versions).
Best Practices
- Choose the Right Method: Use
ILogger
for general application tracing and diagnostics. UseIEventLoomerClient
for explicitly logging key business events or steps defined in EventLoomer. - Use Meaningful Identifiers: Use clear
uniqueIdentifier
values (forSendLogAsync
) orcategoryName
/EventId
(forILogger
/SendApplicationLogAsync
) that align with your application's domain. - Structured Logging (
ILogger
): Leverage structured logging (_logger.LogInformation("User {UserId} logged in", userId);
) for richer, searchable logs. Use scopes (BeginScope
) for contextual data. - Correlation Keys: Consistently apply correlation keys to trace operations across services or asynchronous boundaries.
- Log Levels: Use appropriate levels to differentiate between informational messages, warnings, and critical errors.
- Exception Handling: Include the
Exception
object when logging errors (_logger.LogError(ex, ...)
or_eventLoomerClient.ErrorAsync(..., ex.ToString())
). - Environments: Configure and use the
Environment
property to separate logs logically. - Check Responses: If not failing silently, check
response.Success
fromIEventLoomerClient
calls to handle potential sending errors. - Configuration Validation: Consider using
ValidateConfigurationAsync
at application startup to ensure the SDK is correctly configured.