Helatra.GelfReceiver 2.0.3.17

dotnet add package Helatra.GelfReceiver --version 2.0.3.17
                    
NuGet\Install-Package Helatra.GelfReceiver -Version 2.0.3.17
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Helatra.GelfReceiver" Version="2.0.3.17" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Helatra.GelfReceiver" Version="2.0.3.17" />
                    
Directory.Packages.props
<PackageReference Include="Helatra.GelfReceiver" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Helatra.GelfReceiver --version 2.0.3.17
                    
#r "nuget: Helatra.GelfReceiver, 2.0.3.17"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Helatra.GelfReceiver@2.0.3.17
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Helatra.GelfReceiver&version=2.0.3.17
                    
Install as a Cake Addin
#tool nuget:?package=Helatra.GelfReceiver&version=2.0.3.17
                    
Install as a Cake Tool

Helatra.GelfReceiver

All-in-one GELF log collection, indexing, and analytics package for .NET 9

Receive GELF 1.1 messages over UDP, index them to OpenSearch, query logs programmatically, and expose a ready-to-use REST API — all from a single NuGet package.

  Your App (.NET)
       │
       ▼
  ┌──────────────────────────────┐
  │   Helatra.GelfReceiver       │
  │                              │
  │   UDP :12201 ──► Buffer      │
  │                   │          │
  │                   ▼          │
  │            OpenSearch Sink   │──────► OpenSearch Cluster
  │                              │
  │   REST API  ◄── Query Client │──────► Search / Analytics
  └──────────────────────────────┘

What Does This Package Do?

Problem: You have applications (NGINX, HAProxy, custom services) that emit GELF (Graylog Extended Log Format) messages over UDP. You need to collect, store, search, and analyze these logs — but without running a full Graylog stack.

Solution: Helatra.GelfReceiver replaces the entire Graylog pipeline with a single NuGet package:

Capability Traditional Stack With This Package
Receive GELF UDP Graylog Server AddGelfReceiver()
Store & Index Elasticsearch + Graylog OpenSearch (direct)
Search Logs Graylog UI / API Embedded REST API
Analytics Graylog Dashboards Built-in summary & breakdown endpoints
Integration External system Native .NET DI, runs in your app

Result: One line of code replaces an entire infrastructure component.


Installation

Prerequisites

OpenSearch is required for log storage and querying. Install on your server:

# Ubuntu/Debian
sudo apt-get update && sudo apt-get install -y opensearch

# Or with Docker
docker run -d --name opensearch \
  -p 9200:9200 \
  -e "discovery.type=single-node" \
  -e "DISABLE_SECURITY_PLUGIN=true" \
  opensearchproject/opensearch:2.18.0

NuGet Package

# From Helatra Nexus repository
dotnet add package Helatra.GelfReceiver \
  --source https://artifact.helatra.com/repository/nuget-hosted/index.json

Or add to your .csproj:

<PackageReference Include="Helatra.GelfReceiver" Version="2.0.0" />

If you haven't registered the Nexus source yet:

dotnet nuget add source https://artifact.helatra.com/repository/nuget-hosted/index.json \
  --name Helatra \
  --username jenkins \
  --password YOUR_PASSWORD \
  --store-password-in-clear-text

Quick Start

Minimal Setup (3 lines)

// Program.cs
using Helatra.GelfReceiver.Extensions;

var builder = WebApplication.CreateBuilder(args);

// 1. Register GELF receiver + OpenSearch sink + query client
builder.Services.AddGelfReceiver(builder.Configuration);

// 2. Add controllers with embedded log analytics API
builder.Services.AddControllers()
    .AddGelfReceiverControllers();  // Serves at: /api/v1/logs

var app = builder.Build();
app.MapControllers();
app.Run();

That's it. Your application now:

  • Listens for GELF messages on UDP port 12201
  • Indexes them into OpenSearch with daily rolling indices
  • Exposes 5 REST endpoints for log search and analytics

With Custom Route Prefix

// If your frontend expects a specific route:
builder.Services.AddControllers()
    .AddNewtonsoftJson()
    .AddGelfReceiverControllers("api/v1/LogAnalytics");
    // Endpoints: /api/v1/LogAnalytics/get-table-all, /summary, etc.

Configuration

appsettings.json

{
  "GelfReceiver": {
    "Port": 12201,
    "BindAddress": "0.0.0.0",
    "BufferSize": 500,
    "FlushIntervalSeconds": 5,
    "MaxMessagesPerSecond": 0,
    "ChunkTimeoutSeconds": 5,
    "MaxPendingChunks": 1000,

    "OpenSearch": {
      "Enabled": true,
      "Url": "https://localhost:9200",
      "Username": "admin",
      "Password": "admin",
      "IndexPrefix": "gelf-logs",
      "NumberOfShards": 1,
      "NumberOfReplicas": 0,
      "RetentionDays": 7,
      "SkipCertificateValidation": true
    }
  }
}

Configuration Reference

GelfReceiverOptions
Option Type Default Description
Port int 12201 UDP port to listen on (GELF standard)
BindAddress string 127.0.0.1 Bind address. Use 0.0.0.0 to accept from all interfaces
BufferSize int 500 Max messages to buffer before flushing to OpenSearch
FlushIntervalSeconds int 5 Force flush after N seconds even if buffer isn't full
MaxMessagesPerSecond int 0 Rate limit (0 = unlimited)
ChunkTimeoutSeconds int 5 Timeout for multi-chunk GELF message reassembly
MaxPendingChunks int 1000 Max pending chunk assemblies (prevents memory exhaustion)
OpenSearchSinkOptions
Option Type Default Description
Enabled bool false Enable OpenSearch indexing
Url string https://localhost:9200 OpenSearch endpoint URL
Username string "" Authentication username
Password string "" Authentication password
IndexPrefix string gelf-logs Index name prefix. Creates: {prefix}-2026.03.10
NumberOfShards int 1 Primary shards per daily index
NumberOfReplicas int 0 Replica shards per daily index
RetentionDays int 7 Auto-delete indices older than N days (ISM policy)
SkipCertificateValidation bool true Skip TLS validation (for self-signed certs)

Manual Configuration (without appsettings.json)

builder.Services.AddGelfReceiver(
    receiver =>
    {
        receiver.Port = 12201;
        receiver.BindAddress = "0.0.0.0";
        receiver.BufferSize = 1000;
        receiver.FlushIntervalSeconds = 3;
    },
    openSearch =>
    {
        openSearch.Enabled = true;
        openSearch.Url = "https://opensearch.internal:9200";
        openSearch.Username = "admin";
        openSearch.Password = "StrongPassword123!";
        openSearch.IndexPrefix = "waf-logs";
        openSearch.RetentionDays = 30;
    });

API Endpoints

When AddGelfReceiverControllers() is called, these endpoints are automatically available:

Method Endpoint Auth Description
POST {prefix}/get-table-all Required Paginated log search with advanced filtering
GET {prefix}/summary?range=3600 Required Dashboard summary (total, blocked, errors, top attackers)
GET {prefix}/blocked-count?range=3600 Required Blocked request count widget
GET {prefix}/attack-breakdown?range=3600 Required Attack type distribution (SQL Injection, XSS, etc.)
GET {prefix}/status Anonymous OpenSearch engine health check

POST /get-table-all — Paginated Search

Server-side pagination with filtering, designed for AG Grid / data table integration.

Request:

POST /api/v1/logs/get-table-all

{
  "maxResultCount": 20,
  "skipCount": 0,
  "orderBy": "timestamp desc",
  "keywordSearch": "",
  "searchExpressionList": [
    {
      "propName": "remoteAddr",
      "searchOperator": 0,
      "value1": "192.168.1.100"
    },
    {
      "propName": "status",
      "searchOperator": 7,
      "value1": "399"
    },
    {
      "propName": "range",
      "searchOperator": 0,
      "value1": "86400"
    }
  ]
}

Response:

{
  "totalCount": 1542,
  "items": [
    {
      "id": "abc123",
      "timestamp": "2026-03-10T14:30:00Z",
      "source": "nginx-waf",
      "message": "GET /api/users HTTP/1.1",
      "level": 6,
      "facility": "nginx",
      "remoteAddr": "192.168.1.100",
      "requestUri": "/api/users",
      "requestMethod": "GET",
      "status": 403,
      "httpHost": "app.example.com",
      "httpUserAgent": "Mozilla/5.0",
      "rule": "sqli-detect",
      "eventType": "waf_block"
    }
  ]
}

Search Operators

Value Name Lucene Query Example
0 Equal field:value status:403
1 NotEqual NOT field:value NOT status:200
2 FullLike field:*value* request_uri:*admin*
3 NotFullLike NOT field:*value* NOT request_uri:*css*
4 StartWith field:value* remote_addr:192.168.*
5 EndWith field:*value request_uri:*.php
6 LessThan field:<value status:<400
7 GreaterThan field:>value status:>399
8 LessOrEqual field:<=value status:<=299
9 GreaterOrEqual field:>=value status:>=500
12 Blank NOT _exists_:field Field is empty
13 NotBlank _exists_:field Field has value

Searchable Fields

Frontend Name OpenSearch Field Description
timestamp @timestamp Log timestamp
source host Source hostname
message short_message Log message
level level Syslog level (0-7)
facility facility Log facility
remoteAddr remote_addr Client IP address
requestUri request_uri HTTP request path
requestMethod request_method HTTP method
status status HTTP status code
httpHost http_host Target hostname
httpUserAgent http_user_agent Client user agent
rule rule WAF rule that triggered
eventType event_type Event type (access, waf_block, etc.)

GET /summary — Dashboard Analytics

curl -H "Authorization: Bearer TOKEN" \
  "https://app.example.com/api/v1/logs/summary?range=3600"

Response:

{
  "totalLogs": 15420,
  "blockedRequests": 342,
  "errorRequests": 89,
  "topAttackers": [
    { "ip": "45.33.32.156", "count": 128 },
    { "ip": "104.236.198.48", "count": 67 }
  ],
  "topTargetedUris": [
    { "uri": "/wp-login.php", "count": 203 },
    { "uri": "/admin/config.php", "count": 87 }
  ]
}

GET /attack-breakdown — WAF Attack Distribution

curl -H "Authorization: Bearer TOKEN" \
  "https://app.example.com/api/v1/logs/attack-breakdown?range=86400"

Response:

{
  "SQL Injection": 156,
  "XSS": 89,
  "Path Traversal": 42,
  "Scanner Detection": 234,
  "Protocol Attack": 18
}

GET /status — Health Check (Anonymous)

curl "https://app.example.com/api/v1/logs/status"

Response:

{
  "engine": "OpenSearch",
  "status": "green"
}

Query Client (Programmatic Access)

Inject IGelfLogQueryClient anywhere in your application for direct log access:

using Helatra.GelfReceiver.Query;

public class SecurityDashboardService
{
    private readonly IGelfLogQueryClient _logClient;

    public SecurityDashboardService(IGelfLogQueryClient logClient)
    {
        _logClient = logClient;
    }

    // Search for blocked requests from a specific IP
    public async Task<GelfLogSearchResult> GetBlockedFromIp(string ip)
    {
        return await _logClient.SearchAsync(
            query: $"remote_addr:{ip} AND event_type:waf_block",
            rangeSeconds: 86400,    // last 24 hours
            limit: 100,
            offset: 0,
            sortField: "@timestamp",
            sortOrder: "desc");
    }

    // Get real-time summary for monitoring
    public async Task<GelfLogSummary> GetRealtimeSummary()
    {
        var summary = await _logClient.GetSummaryAsync(rangeSeconds: 300); // last 5 min
        // summary.TotalLogs
        // summary.BlockedRequests
        // summary.ErrorRequests
        // summary.TopAttackers → List<GelfTopAttacker> { Ip, Count }
        // summary.TopTargetedUris → List<GelfTopUri> { Uri, Count }
        return summary;
    }

    // Get attack breakdown for reporting
    public async Task<Dictionary<string, int>> GetDailyAttackReport()
    {
        return await _logClient.GetAttackBreakdownAsync(rangeSeconds: 86400);
        // { "SQL Injection": 156, "XSS": 89, "Scanner Detection": 234, ... }
    }
}

Query Syntax

The search query uses Lucene query string syntax:

# Exact match
status:403

# Wildcard
request_uri:/admin*

# Range
status:>=400 AND status:<500

# Boolean
remote_addr:192.168.* AND NOT event_type:access

# Field exists
_exists_:rule

# Free text (searches short_message)
"SQL injection detected"

Custom Sink

Implement IGelfSink to add your own log processing alongside OpenSearch:

using Helatra.GelfReceiver.Models;
using Helatra.GelfReceiver.Processing;

public class SlackAlertSink : IGelfSink
{
    public string Name => "SlackAlert";

    public async Task HandleBatchAsync(IReadOnlyList<GelfMessage> messages, CancellationToken ct)
    {
        var critical = messages.Where(m => m.Level <= 3); // Emergency, Alert, Critical, Error
        foreach (var msg in critical)
        {
            var ip = msg.GetString("_remote_addr");
            var uri = msg.GetString("_request_uri");
            var rule = msg.GetString("_rule");
            // Send to Slack, PagerDuty, etc.
        }
    }
}

// Register in DI:
builder.Services.AddSingleton<IGelfSink, SlackAlertSink>();

Metrics & Monitoring

Access receiver metrics via DI:

using Helatra.GelfReceiver.Processing;

public class HealthCheckService
{
    private readonly GelfReceiverMetrics _metrics;

    public HealthCheckService(GelfReceiverMetrics metrics)
    {
        _metrics = metrics;
    }

    public object GetMetrics()
    {
        return _metrics.GetSnapshot();
        // {
        //   "received": 150000,
        //   "flushed": 149800,
        //   "dropped": 0,
        //   "pending": 200,
        //   "sinkErrors": { "OpenSearch": 3 }
        // }
    }
}

GELF Message Format

The receiver accepts standard GELF 1.1 messages. Custom fields are prefixed with _:

{
  "version": "1.1",
  "host": "nginx-waf-01",
  "short_message": "GET /api/users HTTP/1.1",
  "timestamp": 1741612800.000,
  "level": 6,
  "_remote_addr": "192.168.1.100",
  "_request_uri": "/api/users",
  "_request_method": "GET",
  "_status": 200,
  "_http_host": "app.example.com",
  "_http_user_agent": "Mozilla/5.0",
  "_rule": "",
  "_event_type": "access"
}

Syslog Levels

Level Name Description
0 Emergency System is unusable
1 Alert Immediate action required
2 Critical Critical conditions
3 Error Error conditions
4 Warning Warning conditions
5 Notice Normal but significant
6 Info Informational messages
7 Debug Debug-level messages

NGINX GELF Output Example

Configure NGINX to send access logs as GELF:

# nginx.conf
log_format gelf_json escape=json
  '{'
    '"version":"1.1",'
    '"host":"$hostname",'
    '"short_message":"$request",'
    '"timestamp":$msec,'
    '"level":6,'
    '"_remote_addr":"$remote_addr",'
    '"_request_uri":"$request_uri",'
    '"_request_method":"$request_method",'
    '"_status":$status,'
    '"_http_host":"$host",'
    '"_http_user_agent":"$http_user_agent",'
    '"_body_bytes_sent":$body_bytes_sent,'
    '"_request_time":$request_time'
  '}';

access_log syslog:server=127.0.0.1:12201 gelf_json;

Test with netcat

echo '{"version":"1.1","host":"test","short_message":"Hello GELF","level":6}' \
  | gzip | nc -u -w1 127.0.0.1 12201

Architecture

                     ┌──────────────┐
                     │  GELF Source  │  (NGINX, HAProxy, Apps)
                     └──────┬───────┘
                            │ UDP :12201
                            ▼
                 ┌─────────────────────┐
                 │   GelfUdpListener   │  Decompression (GZIP/ZLIB)
                 │ GelfChunkAssembler  │  Multi-chunk reassembly
                 └──────────┬──────────┘
                            │ GelfMessage
                            ▼
                 ┌─────────────────────┐
                 │  GelfMessageBuffer  │  Channel-based batching
                 │  (bounded, 10K cap) │  Backpressure: DropOldest
                 └──────────┬──────────┘
                            │ IReadOnlyList<GelfMessage>
                            ▼
              ┌──────────────────────────────┐
              │         IGelfSink[]          │
              │  ┌──────────────────────┐    │
              │  │   OpenSearchSink     │    │──► OpenSearch Cluster
              │  │  (bulk index, ISM)   │    │    Daily: gelf-logs-2026.03.10
              │  └──────────────────────┘    │
              │  ┌──────────────────────┐    │
              │  │  Your Custom Sink    │    │──► Slack, DB, File...
              │  └──────────────────────┘    │
              └──────────────────────────────┘

              ┌──────────────────────────────┐
              │   IGelfLogQueryClient        │
              │  OpenSearchLogQueryClient    │──► OpenSearch (query)
              └──────────────┬───────────────┘
                             │
                             ▼
              ┌──────────────────────────────┐
              │     GelfLogController        │
              │  POST /get-table-all         │──► Paginated search
              │  GET  /summary               │──► Analytics
              │  GET  /attack-breakdown      │──► WAF distribution
              │  GET  /status                │──► Health check
              └──────────────────────────────┘

Key Design Decisions

Decision Rationale
Singleton services Single UDP listener, single buffer — no resource duplication
Channel-based buffer System.Threading.Channels for lock-free producer/consumer
BoundedChannel + DropOldest Backpressure protection — never blocks the UDP listener
Daily rolling indices {prefix}-yyyy.MM.dd — efficient time-range queries
ISM auto-retention OpenSearch automatically deletes indices older than RetentionDays
IApplicationModelConvention Route prefix configurable at startup, no hardcoded paths
IGelfSink interface Extensible — add custom sinks without modifying the package

Full Integration Example

A complete ASP.NET Core Web API with GELF receiver, JWT auth, and log analytics:

using Helatra.GelfReceiver.Extensions;
using Microsoft.AspNetCore.Authentication.JwtBearer;

var builder = WebApplication.CreateBuilder(args);

// Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new()
        {
            ValidateIssuer = true,
            ValidIssuer = "your-app",
            ValidateAudience = false,
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["Auth:SecretKey"]!))
        };
    });

// Controllers + GELF log analytics API
builder.Services.AddControllers()
    .AddGelfReceiverControllers("api/v1/logs");

// GELF Receiver — starts UDP listener as background service
builder.Services.AddGelfReceiver(builder.Configuration);

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();
{
  "Auth": {
    "SecretKey": "your-secret-key-here"
  },
  "GelfReceiver": {
    "Port": 12201,
    "BindAddress": "0.0.0.0",
    "OpenSearch": {
      "Enabled": true,
      "Url": "https://opensearch:9200",
      "Username": "admin",
      "Password": "admin",
      "IndexPrefix": "app-logs",
      "RetentionDays": 30
    }
  }
}

Requirements

  • .NET 9.0 or later
  • OpenSearch 2.x (for sink and query features)
  • ASP.NET Core (for embedded API controller)

License

Proprietary - Helatra

Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.3.17 141 4/28/2026
2.0.3.16 114 4/28/2026