OutWit.Common.Logging.NewRelic
2.0.0
See the version list below for details.
dotnet add package OutWit.Common.Logging.NewRelic --version 2.0.0
NuGet\Install-Package OutWit.Common.Logging.NewRelic -Version 2.0.0
<PackageReference Include="OutWit.Common.Logging.NewRelic" Version="2.0.0" />
<PackageVersion Include="OutWit.Common.Logging.NewRelic" Version="2.0.0" />
<PackageReference Include="OutWit.Common.Logging.NewRelic" />
paket add OutWit.Common.Logging.NewRelic --version 2.0.0
#r "nuget: OutWit.Common.Logging.NewRelic, 2.0.0"
#:package OutWit.Common.Logging.NewRelic@2.0.0
#addin nuget:?package=OutWit.Common.Logging.NewRelic&version=2.0.0
#tool nuget:?package=OutWit.Common.Logging.NewRelic&version=2.0.0
OutWit.Common.Logging.NewRelic
Renamed from
OutWit.Common.NewRelic(v1.x) in v2.0. The neutral model types (LogEntry,LogQuery,LogFilter, …) moved toOutWit.Common.Logging.Query; this package is now the NewRelic-specific backend for that abstraction.
Overview
OutWit.Common.Logging.NewRelic is a .NET client library for querying logs and telemetry data from New Relic via the NerdGraph (GraphQL) API. It converts high-level query objects into NRQL, sends them through NerdGraph, and parses the results into strongly-typed models.
NewRelicProvider implements ILogQueryProvider from OutWit.Common.Logging.Query — consumers depend on the neutral interface and swap backends (NewRelic, Loki, file) without touching their code. NewRelic-specific extras (e.g. the NrConsumption billing breakdown) live behind the additional INewRelicProvider interface.
Key capabilities:
- Paginated log retrieval with offset-based navigation
- Full-text search across log messages
- Strongly-typed filters — no raw NRQL strings required
- Facet extraction (distinct attribute values for filter dropdowns)
- Log statistics — counts and severity distribution over a time range
- Data consumption monitoring — actual GB ingested, free-tier projections, product-line breakdown (via the NewRelic-specific
INewRelicProviderextension)
All models are [MemoryPackable] for efficient binary serialization (e.g. over WitRPC).
Install
Install-Package OutWit.Common.Logging.NewRelic
or
dotnet add package OutWit.Common.Logging.NewRelic
Target Frameworks
net6.0 � net7.0 � net8.0 � net9.0 � net10.0
Getting Started
1. Configure the Client
using OutWit.Common.Logging.NewRelic;
using OutWit.Common.Logging.NewRelic.Model;
using OutWit.Common.Logging.Query.Model;
var options = new NewRelicClientOptions
{
ApiKey = "NRAK-...", // User API key (not license key)
AccountId = 1234567
};
var httpClient = new NewRelicHttpClient(options);
var provider = new NewRelicProvider(httpClient);
NewRelicClientOptions also exposes:
| Property | Default | Description |
|---|---|---|
Endpoint |
https://api.newrelic.com/graphql |
NerdGraph endpoint (override for EU: https://api.eu.newrelic.com/graphql) |
DefaultPageSize |
100 |
Page size when the query does not specify one |
MaxPageSize |
1000 |
Upper clamp for any requested page size |
For unit testing you can inject your own HttpClient:
var httpClient = new NewRelicHttpClient(new HttpClient(mockHandler), options);
2. Query Logs
By absolute time range
var page = await provider.GetLogsAsync(
from: DateTime.UtcNow.AddHours(-1),
to: DateTime.UtcNow,
filters: new[] { LogFilters.LevelAtLeast(LogSeverity.Warning) },
pageSize: 50
);
foreach (var entry in page.Items)
Console.WriteLine($"[{entry.Level}] {entry.Timestamp:HH:mm:ss} {entry.Message}");
if (page.HasMore)
{
// Fetch next page
var next = await provider.GetLogsAsync(
from: DateTime.UtcNow.AddHours(-1),
to: DateTime.UtcNow,
filters: new[] { LogFilters.LevelAtLeast(LogSeverity.Warning) },
pageSize: 50,
offset: page.Offset + page.PageSize
);
}
By lookback window (relative time)
var page = await provider.GetRecentLogsAsync(
lookback: TimeSpan.FromMinutes(15),
filters: new[] { LogFilters.ServiceEquals("my-api") }
);
Full-text search
var page = await provider.SearchAsync(
text: "NullReferenceException",
lookback: TimeSpan.FromHours(1),
extraFilters: new[] { LogFilters.EnvironmentEquals("Production") }
);
Low-level: custom LogQuery
var query = new LogQuery
{
From = DateTime.UtcNow.AddHours(-2),
To = DateTime.UtcNow,
FullTextSearch = "timeout",
Filters = new[]
{
LogFilters.ServiceIn("api-gateway", "auth-service"),
LogFilters.LevelAtLeast(LogSeverity.Error)
},
PageSize = 200,
Offset = 0,
SortOrder = LogSortOrder.Descending
};
var page = await provider.QueryAsync(query);
3. Build Filters
Low-level factory methods on LogFilter
LogFilter.Eq("level", "Error") // level = 'Error'
LogFilter.NotEq("level", "Debug") // level != 'Debug'
LogFilter.Contains("message", "timeout") // message LIKE '%timeout%'
LogFilter.NotContains("message", "health") // message NOT LIKE '%health%'
LogFilter.In("level", "Error", "Critical") // level IN ('Error', 'Critical')
LogFilter.GreaterThan("timestamp", "...") // timestamp > ...
LogFilter.LessOrEqual("duration", "5000") // duration <= 5000
Strongly-typed helpers via LogFilters
The LogFilters static class eliminates magic strings:
// Severity
LogFilters.LevelEquals(LogSeverity.Error)
LogFilters.LevelIn(LogSeverity.Error, LogSeverity.Critical)
LogFilters.LevelAtLeast(LogSeverity.Warning) // Warning + Error + Critical + Fatal
// Message
LogFilters.MessageContains("timeout")
LogFilters.MessageNotContains("healthcheck")
// Service / Environment / Context
LogFilters.ServiceEquals("my-api")
LogFilters.ServiceIn("api-gateway", "auth-service")
LogFilters.EnvironmentEquals("Production")
LogFilters.SourceContextEquals("MyApp.Services.OrderService")
LogFilters.SourceContextIn("MyApp.Services.OrderService", "MyApp.Services.PaymentService")
// Distributed tracing
LogFilters.TraceIdEquals("abc123")
LogFilters.SpanIdEquals("span-456")
4. Log Attributes
LogAttribute defines the well-known log attributes with their common New Relic variations:
| Attribute | Primary name | Recognized variations |
|---|---|---|
Timestamp |
timestamp |
� |
Level |
level |
log.level |
Message |
message |
� |
Host |
hostname |
host, host.name |
ServiceName |
service.name |
serviceName |
SourceContext |
Message.Properties.SourceContext |
SourceContext, logger, logger.name |
Environment |
environment |
env |
Exception |
exception |
� |
TraceId |
trace.id |
traceId |
SpanId |
span.id |
spanId |
Each attribute supports Is(), StartsWith(), and EndsWith() matching (case-insensitive) against both the primary name and all variations.
5. Severity Levels
LogSeverity maps standard log levels with a numeric ordering:
| Level | Numeric |
|---|---|
Trace |
0 |
Debug |
1 |
Information |
2 |
Warning |
3 |
Error |
4 |
Critical |
5 |
Fatal |
6 |
// Get all levels >= Warning
var severe = LogSeverity.LevelAtLeast(LogSeverity.Warning);
// Returns: [Warning, Error, Critical, Fatal]
6. Distinct Attribute Values
Useful for populating filter dropdowns in a UI:
var services = await provider.GetDistinctValuesAsync(
from: DateTime.UtcNow.AddDays(-7),
to: DateTime.UtcNow,
attribute: LogAttribute.ServiceName,
limit: 500
);
// Returns: ["api-gateway", "auth-service", "worker", ...]
7. Find Offset by Timestamp
Navigate to a specific point in the log stream ("scroll to timestamp"):
var query = new LogQuery
{
From = DateTime.UtcNow.AddHours(-6),
To = DateTime.UtcNow,
SortOrder = LogSortOrder.Descending
};
long offset = await provider.FindOffsetAsync(query, targetTimestamp);
query.Offset = (int)offset;
var page = await provider.QueryAsync(query);
8. Log Statistics
Get severity distribution and averages for a time period:
var stats = await provider.GetStatisticsAsync(
from: DateTime.UtcNow.AddDays(-1),
to: DateTime.UtcNow,
filters: new[] { LogFilters.ServiceEquals("my-api") }
);
Console.WriteLine($"Total: {stats.TotalCount}");
Console.WriteLine($"Errors: {stats.ErrorCount} ({stats.ErrorRate:F1}%)");
Console.WriteLine($"Warnings: {stats.WarningCount} ({stats.WarningRate:F1}%)");
Console.WriteLine($"Avg/day: {stats.AverageLogsPerDay:F0}");
LogStatistics provides these computed properties:
| Property | Description |
|---|---|
ErrorRate |
Percentage of Error/Critical/Fatal logs |
WarningRate |
Percentage of Warning logs |
InfoRate |
Percentage of Information logs |
DebugRate |
Percentage of Debug/Trace logs |
DurationDays |
Length of the period in days |
AverageLogsPerDay |
Total / days |
AverageErrorsPerDay |
Errors / days |
AverageWarningsPerDay |
Warnings / days |
9. Data Consumption (Billing)
Monitor actual data ingestion from New Relic's NrConsumption billing event:
var monthStart = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1);
var consumption = await provider.GetDataConsumptionAsync(
from: monthStart,
to: DateTime.UtcNow
);
Console.WriteLine($"Total ingested: {consumption.TotalGigabytes:F2} GB");
Console.WriteLine($"Daily average: {consumption.DailyAverageGigabytes:F2} GB/day");
Console.WriteLine($"Projected EOM: {consumption.ProjectedEndOfMonthGigabytes:F2} GB");
Console.WriteLine($"Free tier used: {consumption.FreeTierUsagePercent:F1}%");
Console.WriteLine($"Free tier left: {consumption.FreeTierRemainingGB:F2} GB");
if (consumption.WillExceedFreeTier)
Console.WriteLine($"? Projected overage: {consumption.ProjectedOverageGB:F2} GB");
// Breakdown by product line
Console.WriteLine($" Logs: {consumption.LogsGigabytes:F2} GB");
Console.WriteLine($" Metrics: {consumption.MetricsGigabytes:F2} GB");
Console.WriteLine($" Traces: {consumption.TracesGigabytes:F2} GB");
Console.WriteLine($" Events: {consumption.EventsGigabytes:F2} GB");
Result Models
LogPage
| Property | Type | Description |
|---|---|---|
Items |
LogEntry[] |
Log entries on the current page |
Offset |
int |
Zero-based offset of this page |
PageSize |
int |
Requested page size |
HasMore |
bool |
true when Items.Length == PageSize (next page likely exists) |
LogEntry
| Property | Type | Description |
|---|---|---|
Timestamp |
DateTime |
Log timestamp (UTC) |
Level |
LogSeverity? |
Parsed severity level |
Message |
string? |
Log message text |
Exception |
string? |
Exception details (message + stack trace) |
SourceContext |
string? |
Logger / source context name |
ServiceName |
string? |
Logical service name (service.name) |
Host |
string? |
Host / machine / container name |
Environment |
string? |
Environment name (dev/staging/prod) |
TraceId |
string? |
Distributed trace identifier |
SpanId |
string? |
Span identifier within a trace |
Architecture
INewRelicProvider (interface)
??? NewRelicProvider (orchestration)
??? NewRelicHttpClient : RestClientBase (HTTP + GraphQL)
??? NrqlRequest : IRequestPost (NRQL ? GraphQL body)
LogQuery ??? NrqlQueryBuilder.BuildNrql() ??? NRQL string
NerdGraph JSON ??? NrqlResponseParser ??? Typed models
Dependencies
| Package | Purpose |
|---|---|
OutWit.Common.Rest |
Base HTTP client (RestClientBase) |
OutWit.Common.MemoryPack |
Binary serialization attributes for models |
License
Licensed under the Apache License, Version 2.0. See LICENSE.
Attribution (optional)
If you use OutWit.Common.NewRelic in a product, a mention is appreciated (but not required), for example: "Powered by OutWit.Common.NewRelic (https://ratner.io/)".
Trademark / Project name
"OutWit" and the OutWit logo are used to identify the official project by Dmitry Ratner.
You may:
- refer to the project name in a factual way (e.g., "built with OutWit.Common.NewRelic");
- use the name to indicate compatibility (e.g., "OutWit.Common.NewRelic-compatible").
You may not:
- use "OutWit.Common.NewRelic" as the name of a fork or a derived product in a way that implies it is the official project;
- use the OutWit.Common.NewRelic logo to promote forks or derived products without permission.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 is compatible. 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. |
-
net10.0
- OutWit.Common.Logging.Query (>= 1.0.0)
- OutWit.Common.MemoryPack (>= 1.1.4)
- OutWit.Common.Rest (>= 1.2.1)
-
net6.0
- OutWit.Common.Logging.Query (>= 1.0.0)
- OutWit.Common.MemoryPack (>= 1.1.4)
- OutWit.Common.Rest (>= 1.2.1)
-
net7.0
- OutWit.Common.Logging.Query (>= 1.0.0)
- OutWit.Common.MemoryPack (>= 1.1.4)
- OutWit.Common.Rest (>= 1.2.1)
-
net8.0
- OutWit.Common.Logging.Query (>= 1.0.0)
- OutWit.Common.MemoryPack (>= 1.1.4)
- OutWit.Common.Rest (>= 1.2.1)
-
net9.0
- OutWit.Common.Logging.Query (>= 1.0.0)
- OutWit.Common.MemoryPack (>= 1.1.4)
- OutWit.Common.Rest (>= 1.2.1)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on OutWit.Common.Logging.NewRelic:
| Package | Downloads |
|---|---|
|
OutWit.Identity.Contracts
Data contracts for WitIdentity administration — application management, dashboard, invitations, and result types. 2.0 swaps vendor-specific NewRelic log models for the neutral OutWit.Common.Logging.Query shape; consumers built against 1.x need to retarget. |
|
|
OutWit.Shared.Logging.Blazor
Blazor WebAssembly log viewer components built on MudBlazor. Toolbar, filter tree, table, and detail panel that consume any OutWit ILogQueryProvider — works with the NewRelic, Loki, and File log provider plugins under OutWit.Shared.Logging.Provider.*. Static assets served at _content/OutWit.Shared.Logging.Blazor/. |
GitHub repositories
This package is not used by any popular GitHub repositories.