-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started
Installation, supported target frameworks, the namespace map, and the first working request in both manual and dependency-injection mode.
LogsParser is a .NET scraping and integration library for arizonarp.logsparser.info — the Arizona RP
game-server log viewer. It performs the site's login and TOTP two-factor flow, fetches pages over HTTP, and turns
the returned HTML into immutable typed records. There is no official API behind it: every model is produced by
hand-rolled parsing of the site's markup.
| Package id | LogsParser |
| Version | 1.2.7 |
| Assembly / root namespace | LogsParser |
| Repository / solution / project folder | LogTools |
| Licence | CC BY-NC 4.0 — non-commercial use only |
The package id and every namespace are LogsParser; the repository, solution and project folder are LogTools. The two names are never interchangeable.
From NuGet:
dotnet add package LogsParser
As an explicit PackageReference:
<ItemGroup>
<PackageReference Include="LogsParser" Version="1.2.7" />
</ItemGroup>Or, when consuming the sources directly from a checkout of the repository, as a ProjectReference to
LogTools.csproj (note the project file name — it is not LogsParser.csproj):
<ItemGroup>
<ProjectReference Include="..\LogTools\LogTools.csproj" />
</ItemGroup>The library multi-targets four frameworks and is built with these compiler settings:
| Property | Value |
|---|---|
TargetFrameworks |
net7.0;net8.0;net9.0;net10.0 |
LangVersion |
latest |
Nullable |
enable |
ImplicitUsings |
enable |
GenerateDocumentationFile |
true |
Because net7.0 is the floor, every BCL API used by the library must exist there; newer APIs are polyfilled
internally instead of raising the floor. Nullable reference types are enabled throughout, so optional values are
declared as nullable (LogsParserCredentials?, ICookieStorage?, LogPageMetaInfo?) and non-nullable members
are guaranteed to be non-null — collections are Array.Empty<T>() rather than null when absent.
Exactly two, both pinned per target framework:
| Target framework | Microsoft.Extensions.DependencyInjection |
Microsoft.Extensions.Logging.Abstractions |
|---|---|---|
net7.0 |
7.0.0 |
7.0.1 |
net8.0 |
8.0.1 |
8.0.2 |
net9.0 |
9.0.3 |
9.0.3 |
net10.0 |
10.0.5 |
10.0.5 |
No HTML parsing library is referenced. All markup handling is hand-rolled regex work over the site's real
markup — that is a deliberate design decision, not an omission. Note that only the logging abstractions are
referenced: to call AddLogging() or a concrete provider you add Microsoft.Extensions.Logging (or
Microsoft.Extensions.Hosting) to your own application.
Folder names inside the repository deliberately do not match namespaces. Never infer a namespace from a file
path — take it from the namespace statement, or from this table.
| Namespace | What lives there |
|---|---|
LogsParser |
LogsParserClient, LogsHtmlParser, LogsRequestUriBuilder, ParserRequest, ParserCookie
|
LogsParser.Abstractions |
ILogsParserDataSource, ICookieStorage, MemoryCookieStorage
|
LogsParser.Models |
every request, response and configuration record — LogsQuery, AdminActivityQuery, TopOperationsQuery, LogsPage, LogEntry, LogsAccount, LogsFilterCatalog, AdminActivityReport, TopOperationsReport, LogsParserCredentials, LogsParserHttpOptions, LogsParserRegistrationOptions
|
LogsParser.Net |
LogsParserHttpDataSource |
LogsParser.Parsing |
LogsFilterCatalogParser |
LogsParser.Diagnostics |
LogsParserLogging |
LogsParser.DependencyInjection |
LogsParserServiceCollectionExtensions |
LogsParser.Exceptions |
every exception type, in one flat namespace |
Three examples of the mismatch: Contracts/ICookieStorage.cs is LogsParser.Abstractions,
Infrastructure/Http/LogsParserHttpDataSource.cs is LogsParser.Net, and Parsing/LogsHtmlParser.cs is the root
LogsParser while every other file in Parsing/ is LogsParser.Parsing.
Three objects are involved: a cookie store, a data source that owns the HTTP transport, and the client facade that turns HTML into models.
public LogsParserHttpDataSource(
LogsParserCredentials? credentials = null,
ICookieStorage? cookieStorage = null,
LogsParserHttpOptions? options = null,
HttpClient? httpClient = null,
ILoggerFactory? loggerFactory = null)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/"),
MaxRetryAttempts = 5,
WaitForRateLimitReset = true
});
var client = new LogsParserClient(dataSource);
var page = await client.GetLogsAsync(new LogsQuery(
ServerId: 201,
Filters: ["warn", "mute"],
PeriodFrom: DateTime.UtcNow.AddDays(-1),
PeriodTo: DateTime.UtcNow,
Page: 1,
Limit: 1000));
Console.WriteLine($"{page.Entries.Count} entries, account: {page.Account?.Nickname}");
foreach (var entry in page.Entries)
{
Console.WriteLine($"{entry.Timestamp:u} {entry.Text}");
}LogsParserHttpDataSource implements IDisposable; using var matters because the data source creates and owns
an internal HttpClient whenever httpClient is left null. If you pass your own HttpClient, the data source
does not dispose it, and its handler must have AllowAutoRedirect = false — see
Transport and Authentication.
LogsParserCredentials and LogsParserHttpOptions defaults:
public sealed record LogsParserCredentials(string Login, string Password, string TotpSecret);Property of LogsParserHttpOptions
|
Type | Default | Description |
|---|---|---|---|
BaseUri |
Uri |
new("https://arizonarp.logsparser.info/") |
Base address applied to the internal HttpClient
|
UserAgent |
string |
a Chrome 128 desktop UA string | Value of the User-Agent request header |
Accept |
string |
the browser-like text/html,… list |
Value of the Accept request header |
MaxRetryAttempts |
int |
5 |
Bound on retries for transient failures |
WaitForRateLimitReset |
bool |
true |
On 429, wait until the reset time instead of throwing |
Credentials are optional. Constructing the data source without them is legitimate for a session that is already
authenticated through a restored cookie store; if the service then asks for authentication, the request fails with
AuthenticationRequiredException.
| Exception | When |
|---|---|
AuthenticationRequiredException |
The service demanded login or two-factor confirmation and no LogsParserCredentials were configured |
AuthenticationFailedException |
The login flow did not stabilise after 3 attempts |
TwoFactorAuthenticationException |
TOTP generation, timezone resolution, or two-factor confirmation failed |
CsrfTokenNotFoundException |
An auth page contained no <meta name="csrf-token">
|
AccountConfigurationException |
The account is not configured and the service redirected to /profile
|
ReactShieldBypassException |
The anti-DDoS challenge kept being served after 3 solved tokens |
RateLimitExceededException |
429 with WaitForRateLimitReset = false, or the retry budget was spent |
LogsParserHttpException |
A non-success status code, or a transient failure that outlived MaxRetryAttempts
|
All of them derive from LogsParserException, so a single catch (LogsParserException) covers the library.
See Exceptions.
public static IServiceCollection AddLogsParser(
this IServiceCollection services,
Action<LogsParserRegistrationOptions> configure)using LogsParser;
using LogsParser.DependencyInjection;
using LogsParser.Models;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddLogging();
services.AddLogsParser(options =>
{
options.Credentials = new LogsParserCredentials(
Login: "my_login",
Password: "my_password",
TotpSecret: "BASE32SECRET");
options.HttpOptions = new LogsParserHttpOptions
{
MaxRetryAttempts = 5,
WaitForRateLimitReset = true
};
});
await using var provider = services.BuildServiceProvider();
using var scope = provider.CreateScope();
var client = scope.ServiceProvider.GetRequiredService<LogsParserClient>();
var page = await client.GetLogsAsync(new LogsQuery(ServerId: 201));AddLogging() is registered first so that the ILoggerFactory exists when the data source is constructed; the
registration reads it out of the provider and installs it into LogsParserLogging. Without it, the library falls
back to NullLoggerFactory and stays silent. AddLogging itself comes from the Microsoft.Extensions.Logging
package, which the library does not reference on your behalf.
LogsParserRegistrationOptions:
| Property | Type | Default | Description |
|---|---|---|---|
Credentials |
LogsParserCredentials? |
null |
Registered as a singleton only when non-null |
HttpOptions |
LogsParserHttpOptions |
new() |
Registered as a singleton |
CookieStorageFactory |
Func<IServiceProvider, ICookieStorage>? |
null |
Replaces the default singleton MemoryCookieStorage
|
DataSourceFactory |
Func<IServiceProvider, ILogsParserDataSource>? |
null |
Replaces the default transient LogsParserHttpDataSource
|
Resolve the client through a scope, as above: ILogsParserDataSource is registered as transient and
LogsParserHttpDataSource is IDisposable, so the container disposes each instance together with the scope that
resolved it. A parameterless AddLogsParser() overload exists as well and registers the same graph with default
options and no credentials. Full details in Dependency Injection.
There is no LoginAsync, no SignInAsync, and no "connect first" step — authentication is purely reactive.
LogsParserHttpDataSource sends the data request first, with AllowAutoRedirect = false, and reads the 302
Location header the service replies with as a protocol signal:
| Redirect target | What the data source does |
|---|---|
/login |
Full login: fetch the CSRF token, POST login and password, then fall through to two-factor confirmation |
/authenticator |
Two-factor confirmation only — the password is not re-submitted (a session whose 2FA window lapsed) |
/profile |
Throws AccountConfigurationException — the account itself is not usable |
After a successful authentication the original request is retried automatically, so the call the caller made is the
call that returns data. Practical consequence: the very first GetLogsAsync of a process may perform the entire
login plus TOTP flow and therefore take noticeably longer than the ones after it. Persist the cookie store between
runs to skip it — see Cookie Storage.
The TotpSecret is the raw Base32 secret from the authenticator app. The library does not extract it from a QR
code or a migration URI; it only consumes the final string. The full state machine, retry counters, rate-limit
behaviour and anti-DDoS challenge handling are documented in
Transport and Authentication.
The parsers are pure static functions over strings and have no dependency on the transport, so HTML obtained elsewhere — a file, a proxy, another service — can be parsed directly.
public static LogsPage ParseLogs(string html)using LogsParser;
using LogsParser.Models;
string html = await File.ReadAllTextAsync("logs.html");
LogsPage page = LogsHtmlParser.ParseLogs(html);
foreach (var entry in page.Entries)
{
Console.WriteLine($"{entry.Timestamp:u} {entry.Text}");
}LogsHtmlParser lives in the root LogsParser namespace, not in LogsParser.Parsing. ParseLogs throws
ArgumentNullException / ArgumentException when html is null, empty or whitespace, and degrades to an empty
result when the expected markup is simply absent — unlike ParseAdminActivity and ParseTopOperations, which
throw HtmlParsingException. See Parsers.
| Page | What it covers |
|---|---|
| Home | Overview of the library and the wiki index |
| LogsParserClient | The high-level facade: every method, parameter and return type |
| Requests and URI Builder |
LogsQuery, AdminActivityQuery, TopOperationsQuery and LogsRequestUriBuilder normalisation rules |
| Models | Reference for every public record returned by the library |
| Parsers |
LogsHtmlParser and LogsFilterCatalogParser used standalone |
| Transport and Authentication |
ILogsParserDataSource, the auth state machine, retries, rate limiting, the React challenge |
| Cookie Storage | The ICookieStorage contract and persisting a session across restarts |
| Dependency Injection |
AddLogsParser, registration options, service lifetimes |
| Logging |
LogsParserLogging, categories and the level taxonomy |
| Exceptions | The exception hierarchy and how to handle it |
LogsParser · CC BY-NC 4.0 — non-commercial use only / только некоммерческое использование
English
- Home
- Getting Started
- LogsParserClient
- Requests and URI Builder
- Models
- Parsers
- Transport and Authentication
- Cookie Storage
- Dependency Injection
- Logging
- Exceptions
Русский
- Главная
- Начало работы
- LogsParserClient
- Запросы и построитель URI
- Модели
- Парсеры
- Транспорт и авторизация
- Хранение cookies
- Внедрение зависимостей
- Логирование
- Исключения