LogTailer.NET 1.3.1

The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package LogTailer.NET --version 1.3.1
                    
NuGet\Install-Package LogTailer.NET -Version 1.3.1
                    
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="LogTailer.NET" Version="1.3.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="LogTailer.NET" Version="1.3.1" />
                    
Directory.Packages.props
<PackageReference Include="LogTailer.NET" />
                    
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 LogTailer.NET --version 1.3.1
                    
#r "nuget: LogTailer.NET, 1.3.1"
                    
#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 LogTailer.NET@1.3.1
                    
#: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=LogTailer.NET&version=1.3.1
                    
Install as a Cake Addin
#tool nuget:?package=LogTailer.NET&version=1.3.1
                    
Install as a Cake Tool

LogTailer.NET

Stream tailed log files to the browser — a tail -F with a UI.

A dependency-free ASP.NET Core library with an embedded browser client and native WebSocket streaming, inspired by frontail. It ships two ways:

  • LogTailer.NET — a NuGet package you add to an existing ASP.NET Core app, mounting the log UI on a path of your choosing.
  • LogTailerServer — a standalone web server you install on a box to read any service's log files, whether or not that service is .NET.

Features

  • Follows one or more files like tail -F, coping with rotation and truncation, cross-platform.
  • Seeds each new browser client with the last N lines, then streams live ones.
  • Native WebSockets — no SignalR, no socket.io, no client-side build step.
  • Word and line highlighting driven by your own code.
  • Auto-scroll, pause, click-to-mark, regex filter box, and an unread-count tab badge.
  • Zero package dependencies: just a framework reference to Microsoft.AspNetCore.App.

Install

dotnet add package LogTailer.NET

Quick start

builder.Services.AddLogTailer(options =>
{
    options.RequestPath = "/logs";
    options.PageTitle = "My App";
    options.Files.Add("logs/server.log");
});

var app = builder.Build();

app.UseLogTailer();

Or bind an appsettings.json section instead:

builder.Services.AddLogTailer(builder.Configuration.GetSection("LogTailer"));
{
  "LogTailer": {
    "RequestPath": "/logs",
    "Files": [ "/var/log/myapp.log" ],
    "StartingLines": 100
  }
}

UseLogTailer() does nothing when no files are configured, so the call can stay in your pipeline permanently and the feature switched on or off from config alone.

The endpoint is unauthenticated. Anyone who can reach RequestPath can read your logs, which routinely contain tokens, personal data and internal hostnames. Guard the path with your own middleware, or keep the app off the public internet.

The page is served no-store and its assets no-cache with an ETag. Leave that alone: the page is rendered per request, so caching it freezes the title, the file list and the background colour at the browser's first fetch instead of resolving them on every load.

Options

Option Description Default
RequestPath URL the UI is served from. / serves it at the application root /logs
Files Paths to tail, absolute or relative (empty — disabled)
StartingLines History lines sent on connect, and the server ring-buffer size 100
BrowserLines Maximum lines kept in the browser DOM 2000
PageTitle Tab and topbar title. Used when no ILogTailerPolicy is registered, or when its GetPageTitleOverride() returns null Log Tailer
IsTopbarHidden Hide the topbar false
IsIndentDisabled Disable the hanging indent on wrapped lines false
IsFileNamePrefixEnabled Prefix each line with its file name (automatic when tailing more than one file) false
BackgroundColor Page background #060606
PollInterval How often the server re-reads a file when the file-system watcher misses a change 500 ms
IsPollingFallbackEnabled Serve lines over plain HTTP to browsers whose WebSocket cannot connect true
FallbackPollingInterval How often the browser asks for new lines once it has fallen back to polling 2 s
KeepAliveInterval How often each client is sent a WebSocket keepalive frame. Must stay below the shortest idle timeout between the server and the browser 30 s

PollInterval and FallbackPollingInterval are unrelated despite the similar names: the first is how the server watches files, the second is how a browser without a working WebSocket asks for lines.

When the WebSocket won't connect

Some networks, proxies and browser configurations refuse WebSocket upgrades while ordinary HTTP keeps working. Rather than show an empty page, the client falls back to polling RequestPath/poll after three failed attempts, and keeps retrying the socket every 30 seconds in the background so it recovers on its own.

While the fallback is active, two buttons appear in the topbar next to a status indicator:

Button Effect
Retry WS Issues one ordinary HTTP request, shows its result, then retries the socket immediately. The request matters as much as the retry: it clears a pooled connection the browser wrongly believes is alive, and when that doesn't help, its result (basic 200, opaqueredirect, failed: …) names the failure.
Disable Polling Stops the fallback so the raw WebSocket failure can be observed without polling masking it. Remembered for the browser session; press again to re-enable.

Both transports carry the same messages and share a cursor, so switching between them neither loses nor repeats a line. If a client is away long enough for lines to age out of the server's ring buffer, the gap is marked inline as ==> N lines skipped <== rather than passed off as continuous.

Two query parameters help when diagnosing this:

Parameter Effect
?nows=1 Skip the WebSocket entirely and go straight to polling. Useful for exercising the fallback without breaking a socket.
?nopoll=1 Start with polling disabled, so a WebSocket failure shows as a dead page.

Dynamic values — ILogTailerPolicy

Some things aren't known when the pipeline is built. A page title that carries the machine's public IP, for instance, can't be a constant passed at startup — the IP isn't resolved yet. Register an ILogTailerPolicy and LogTailer asks for those values while serving instead:

public sealed class MyLogTailerPolicy(IHostEnvironment environment) : ILogTailerPolicy
{
    private static readonly HighlightConfig Highlight = new()
    {
        Words = new Dictionary<string, string>
        {
            ["ERROR"] = "color: #ff4d4d;",
            ["WARN"] = "color: orange;",
        },
        Lines = new Dictionary<string, string>
        {
            ["Unhandled exception"] = "font-weight: bold; color: #ff4d4d;",
        },
    };

    public string GetPageTitleOverride() => $"MyApp [{environment.EnvironmentName}] {Environment.MachineName}";

    public HighlightConfig? GetHighlight() => Highlight;
}
builder.Services.AddSingleton<ILogTailerPolicy, MyLogTailerPolicy>();
  • GetPageTitleOverride() is called on every page load, falling back to LogTailerOptions.PageTitle when it returns null or whitespace.
  • GetHighlight() is called each time a browser connects, so changes reach new clients without a restart. Returning null disables highlighting.
  • The policy is optional, but it is the only way to configure highlighting — there's deliberately no preset-file option in the library. See LogTailerServer for a host whose policy layers a file-driven preset on top of a built-in default.
  • Register exactly one. LogTailer throws at startup if it finds more than one registration, rather than silently picking one and leaving the other looking live.
  • It must be safe to resolve as a singleton.

Highlighting

Words wraps every matching substring in a <span> carrying the given inline CSS. Lines styles the whole line when it contains the key. Keys are literal text, matched case-sensitively — not regular expressions — so failed and Failed are separate entries. Note the contrast with the UI's filter box, which is case-insensitive.

Standalone server

LogTailerServer is a small ASP.NET Core host wrapping the library, for tailing services that aren't .NET apps — nginx, PostgreSQL, a Python daemon, anything writing to a file.

dotnet publish LogTailerServer -c Release -o /opt/logtailer

How it reads its configuration depends on the environment, and the two paths share nothing:

  • In Development it binds the LogTailer section of appsettings.json, so every option in the Options table is available from config or the command line.
  • In any other environment — which includes every published deployment — that section is ignored entirely and the options come from environment variables instead.

Development

ASPNETCORE_ENVIRONMENT=Development /opt/logtailer/LogTailerServer \
  --LogTailer:Files:0=/var/log/nginx/error.log \
  --LogTailer:PageTitle=nginx

Deployed

LOG_FILES=/var/log/nginx/error.log,/var/log/nginx/access.log \
APP_NAME=nginx \
STYLES_CONFIG=DEFAULT \
/opt/logtailer/LogTailerServer
Variable Description
LOG_FILES Required. Comma-separated paths to tail. Startup fails if it is unset, or if any listed file does not exist
APP_NAME Name in the page title, assembled as {APP_NAME} [{Environment}] {IP_ADDRESS}, defaulting to LogTailer
IP_ADDRESS Appended to the page title when set — the host's public IP is the usual value
STYLES_CONFIG DEFAULT for the built-in highlighting, or a path to a highlight JSON file. Any other value disables highlighting

The rest is fixed on this path: the UI is served from the application root, with 100 seeded lines, a 2000-line browser buffer, a #060606 background and a 500 ms poll interval.

A STYLES_CONFIG file is read once at startup and takes the shape of a HighlightConfig. Property names are case-insensitive; the highlight keys inside them are not:

{
  "words": {
    "ERROR": "color: #ff4d4d;",
    "WARN": "color: orange;"
  },
  "lines": {
    "FATAL": "font-weight: bold; color: #ff4d4d;"
  }
}

The built-in DEFAULT set targets the level markers common to most log formats (ERROR, WARN, INFO, DEBUG, TRACE, plus FATAL and stack traces). It lives in ServerLogTailerPolicy, which is also where the STYLES_CONFIG handling sits — edit that class to change either.

It binds to http://127.0.0.1:5080 by default — loopback only, on the assumption that exposing logs beyond the machine should be a deliberate act. Override with ASPNETCORE_URLS, and put a reverse proxy or a VPN in front of it when you need remote access.

Using the UI

Filter Type in the box. Tab focuses it, Esc clears it, and the value round-trips through the ?filter= query parameter so a filtered view is shareable. Treated as a case-insensitive regex, falling back to substring matching when it doesn't compile.
Pause Freezes the view and shows a running count of skipped lines.
Mark a line Click it.
Unread count While the window is unfocused, new lines increment a counter in the tab title.
Connection A Disconnected - reconnecting... badge appears when the WebSocket drops, and clears once it is back. It sits outside the topbar, so it stays visible with IsTopbarHidden.

Auto-scroll sticks to the bottom only when you're already there, so scrolling up to read isn't interrupted. ANSI escape sequences are stripped, and the client reconnects automatically if the server restarts.

A tailed file that stays quiet leaves the WebSocket silent, and proxies reap connections they think are idle, so the server sends a keepalive frame every KeepAliveInterval. Behind a load balancer or tunnel, check that value against the shortest idle timeout on the path -- an AWS ALB defaults to 60 seconds.

Requirements

.NET 10. The library targets net10.0 and framework-references Microsoft.AspNetCore.App.

License

MIT

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

    • No dependencies.

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