LogsParser 1.2.4
dotnet add package LogsParser --version 1.2.4
NuGet\Install-Package LogsParser -Version 1.2.4
<PackageReference Include="LogsParser" Version="1.2.4" />
<PackageVersion Include="LogsParser" Version="1.2.4" />
<PackageReference Include="LogsParser" />
paket add LogsParser --version 1.2.4
#r "nuget: LogsParser, 1.2.4"
#:package LogsParser@1.2.4
#addin nuget:?package=LogsParser&version=1.2.4
#tool nuget:?package=LogsParser&version=1.2.4

LogsParser
LogsParser is a .NET library for working with arizonarp.logsparser.info.
It is designed as a reusable integration library first:
- parse logs, admin activity, and top operations
- authenticate with login, password, and TOTP 2FA
- bypass the React anti-DDoS challenge automatically
- expose current account information from page layout
- expose the current filters catalog and
dynamic[n]additional parameters - keep cookie persistence under caller control
- work both manually and through DI
Features
LogsParserClientfor high-level operationsLogsParserHttpDataSourcefor HTTP transportLogsHtmlParserfor raw HTML parsingLogsRequestUriBuilderfor low-level request generationICookieStoragefor caller-owned cookie persistence- automatic login flow
- TOTP 2FA support
- automatic React challenge bypass
- retry and rate-limit handling with
X-Ratelimit-Resetsupport - DI registration extensions
Microsoft.Extensions.Loggingintegration- domain-specific exceptions
Target Frameworks
.NET 7,.NET 8,.NET 9,.NET 10- C#
latest
Project Structure
LogTools/
Client/
Contracts/
DependencyInjection/
Diagnostics/
Exceptions/
Infrastructure/
Models/
Parsing/
Main entry points:
LogsParserClientLogsParserHttpDataSourceLogsHtmlParserLogsParserServiceCollectionExtensions
Installation
NuGet:
dotnet add package LogsParser
Or via ProjectReference:
<ItemGroup>
<ProjectReference Include="..\LogTools\LogTools.csproj" />
</ItemGroup>
Quick Start
Manual Mode
using LogsParser;
using LogsParser.Abstractions;
using LogsParser.Models;
using LogsParser.Net;
var cookies = new MemoryCookieStorage();
using var dataSource = new LogsParserHttpDataSource(
credentials: new LogsParserCredentials(
Login: "my_login",
Password: "my_password",
TotpSecret: "BASE32SECRET"),
cookieStorage: cookies,
options: new LogsParserHttpOptions
{
BaseUri = new Uri("https://arizonarp.logsparser.info/")
});
var client = new LogsParserClient(dataSource);
var logs = await client.GetLogsAsync(new LogsQuery(
ServerId: 201,
Filters: ["warn", "mute"],
PeriodFrom: DateTime.UtcNow.AddDays(-1),
PeriodTo: DateTime.UtcNow,
Limit: 1000));
DI Mode
using LogsParser.DependencyInjection;
using LogsParser.Models;
services.AddLogging();
services.AddLogsParser(options =>
{
options.Credentials = new LogsParserCredentials(
Login: "my_login",
Password: "my_password",
TotpSecret: "BASE32SECRET");
options.HttpOptions = new LogsParserHttpOptions
{
BaseUri = new Uri("https://arizonarp.logsparser.info/")
};
});
Authentication
LogsParserHttpDataSource can perform the full authentication flow automatically:
- open
/login - extract CSRF token
- submit login and password
- open
/authenticator - extract CSRF token
- generate TOTP code
- submit 2FA code
- continue the original request
Credentials model:
new LogsParserCredentials(
Login: "my_login",
Password: "my_password",
TotpSecret: "BASE32SECRET");
Getting TotpSecret
If the account is protected by TOTP and you do not have the raw secret yet:
- Open Google Authenticator → Transfer accounts → Export accounts
- Scan the generated QR code with any QR reader to get the
otpauth-migration://offline?data=...URI - Decode the URI using
otpauth-migration-decoder:python decoder.py decode --migration "otpauth-migration://offline?data=..." - The output will contain standard
otpauth://totp/...?secret=BASE32SECRET&...links — use thesecretparameter value asTotpSecret
The library does not extract the secret for you. It only consumes the final Base32 secret string.
If credentials are not configured and the service redirects to /login, the library throws AuthenticationRequiredException.
React Challenge Bypass
The transport layer includes automatic anti-DDoS handling:
- challenge detection
- payload extraction from the page script
- token derivation
R3ACTLBcookie update- retry of the original request
This behavior is internal to LogsParserHttpDataSource.
Rate Limiting
LogsParserHttpDataSource tracks rate limit headers from the server:
| Property | Header | Description |
|---|---|---|
RateLimitMax |
X-Ratelimit-Limit |
Maximum requests allowed |
RateLimitRemaining |
X-Ratelimit-Remaining |
Remaining requests in current window |
RateLimitReset |
X-Ratelimit-Reset |
Exact time when the limit resets (Unix timestamp) |
Behavior on 429
When a 429 Too Many Requests response is received, the behavior depends on the WaitForRateLimitReset option:
WaitForRateLimitReset |
Behavior |
|---|---|
true (default) |
Waits until the exact reset time from X-Ratelimit-Reset (+1s margin), then retries. This wait does not count as a retry attempt. Falls back to Retry-After / exponential backoff if the header is missing. |
false |
Immediately throws RateLimitExceededException with ResetAt populated so the caller can decide when to retry. |
Configuration:
var options = new LogsParserHttpOptions
{
WaitForRateLimitReset = true // default - wait for reset automatically
};
Handling the exception when WaitForRateLimitReset = false:
catch (RateLimitExceededException ex)
{
Console.WriteLine($"Retry after: {ex.RetryAfterSeconds}s");
if (ex.ResetAt is { } resetAt)
{
Console.WriteLine($"Limit resets at: {resetAt:u}");
}
}
Cookie Storage
The library does not own cookie persistence.
It uses the ICookieStorage contract:
public interface ICookieStorage
{
IReadOnlyCollection<ParserCookie> GetCookies();
void SetCookies(IReadOnlyCollection<ParserCookie> cookies);
}
Default implementation:
MemoryCookieStorage
If cookies must survive process restarts, implement your own storage:
- file-based storage
- database storage
- encrypted secrets storage
- distributed cache
High-Level API
Get Logs
var result = await client.GetLogsAsync(new LogsQuery(
ServerId: 201,
Filters: ["warn", "mute"],
PeriodFrom: DateTime.UtcNow.AddDays(-7),
PeriodTo: DateTime.UtcNow,
Page: 1,
Limit: 1000));
LogsPage contains:
- parsed log entries
- page meta info when available
- current account context in
LogsPage.Account
Get Current Account
var account = await client.GetCurrentAccountAsync();
LogsAccount contains:
NicknameBadgesAvailableServers
This data is extracted from the shared page layout, so a host application does not need to scrape the navbar separately.
Get Filters Catalog
var catalog = await client.GetLogsFilterCatalogAsync();
LogsFilterCatalog contains:
- the current filter list from
type[] - the current account context in
LogsFilterCatalog.Account - per-filter
AdditionalParameters
AdditionalParameters are the dynamic fields from the logs page, for example dynamic[123].
Example:
var catalog = await client.GetLogsFilterCatalogAsync();
foreach (var filter in catalog.Filters)
{
Console.WriteLine($"{filter.Code} -> {filter.Name}");
foreach (var parameter in filter.AdditionalParameters)
{
Console.WriteLine($" {parameter.QueryKey} | {parameter.Label}");
}
}
Get Admin Activity
var activity = await client.GetAdminActivityAsync(
new AdminActivityQuery(
PeriodFrom: DateTime.UtcNow.AddDays(-7),
PeriodTo: DateTime.UtcNow));
Get Top Operations
var top = await client.GetTopOperationsAsync(
new TopOperationsQuery(
Filter: "bank",
Date: DateTime.UtcNow.Date));
Low-Level API
Build Request URI
var uri = LogsRequestUriBuilder.BuildLogsUri(new LogsQuery(
ServerId: 201,
Player: "Some_Nick"));
Parse Raw HTML
string html = await File.ReadAllTextAsync("logs.html");
var parsed = LogsHtmlParser.ParseLogs(html);
Useful when:
- HTTP is handled outside the library
- another service is responsible for authorization
- parsing should be tested separately from transport
Models
Request models:
LogsQueryAdminActivityQueryTopOperationsQuery
Transport and configuration models:
ParserRequestParserCookieLogsParserCredentialsLogsParserHttpOptionsLogsParserRegistrationOptions
Response models:
LogsPageLogEntryLogParticipant— per-participant data (Money, Bank, Donate, AdditionalInfo, LastIp, RegistrationIp)LogAdditionalInfo— extended account data (AccountId, VC, SubAccount1–6, Deposit, AdminLevel)LogPageMetaInfoLogsAccountLogsAccountBadgeLogsAccountServerLogsFilterCatalogLogsFilterDefinitionLogsFilterAdditionalParameterAdminActivityReportTopOperationsReport
Each LogEntry contains Sender (I) and Target (II) as LogParticipant?. When a log record involves two participants, both are populated with their own financial data, additional info, and IP addresses.
All public models are immutable record types.
Logging
The library uses Microsoft.Extensions.Logging through an internal LogsParserLogging facade with thread-safe logger caching.
DI Mode
Logging is configured automatically when ILoggerFactory is registered in the DI container:
services.AddLogging(builder => builder.AddConsole());
services.AddLogsParser(options => { /* ... */ });
Manual Mode
using LogsParser.Diagnostics;
LogsParserLogging.UseLoggerFactory(myLoggerFactory);
Log Levels
| Level | What is logged |
|---|---|
Trace |
Cookie operations, CSRF token extraction, individual HTTP requests, rate limit changes |
Debug |
API call parameters, HTML content sizes, parsing summaries, auth flow steps |
Information |
API call results (entry counts), auth flow start/completion, React challenge bypass |
Warning |
Rate limit exceeded, transient retries, TOTP rejection, missing account info |
Error |
HTTP failures, account configuration errors, unparseable challenge pages |
If no logger is configured, the library safely falls back to NullLogger.
Exceptions
Base exception:
LogsParserException
Parsing:
HtmlParsingException
HTTP and authentication:
LogsParserHttpExceptionAuthenticationRequiredExceptionAuthenticationFailedExceptionTwoFactorAuthenticationExceptionCsrfTokenNotFoundExceptionAccountConfigurationExceptionReactShieldBypassExceptionRateLimitExceededException
Example:
try
{
var logs = await client.GetLogsAsync(new LogsQuery(ServerId: 201));
}
catch (AuthenticationRequiredException)
{
// credentials are missing
}
catch (AuthenticationFailedException)
{
// login or password is invalid
}
catch (TwoFactorAuthenticationException)
{
// TOTP or 2FA flow failed
}
catch (RateLimitExceededException ex)
{
Console.WriteLine($"Retry after: {ex.RetryAfterSeconds}s");
if (ex.ResetAt is { } resetAt)
{
Console.WriteLine($"Limit resets at: {resetAt:u}");
}
}
catch (LogsParserException ex)
{
Console.WriteLine(ex.Message);
}
DI Registration
services.AddLogsParser(options =>
{
options.Credentials = new LogsParserCredentials("login", "password", "secret");
options.CookieStorageFactory = _ => new MemoryCookieStorage();
options.HttpOptions = new LogsParserHttpOptions
{
MaxRetryAttempts = 5,
WaitForRateLimitReset = true
};
});
You can also replace the transport completely:
services.AddLogsParser(options =>
{
options.DataSourceFactory = provider => new MyCustomLogsParserDataSource();
});
Build
$env:DOTNET_CLI_HOME='C:\Users\boss\source\repos\LogTools\.dotnet'
$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE='1'
dotnet build
License
This project is licensed under CC BY-NC 4.0.
Commercial use is not permitted.
See LICENSE.
Notes
- The library is intended for integration scenarios first.
- It can be used both with and without DI.
- Cookie persistence remains the caller's responsibility.
- The transport layer is reusable, but parsing can also be used independently.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- Microsoft.Extensions.DependencyInjection (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
-
net7.0
- Microsoft.Extensions.DependencyInjection (>= 7.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 7.0.1)
-
net8.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
-
net9.0
- Microsoft.Extensions.DependencyInjection (>= 9.0.3)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.