AmLog.Format
1.0.1
dotnet add package AmLog.Format --version 1.0.1
NuGet\Install-Package AmLog.Format -Version 1.0.1
<PackageReference Include="AmLog.Format" Version="1.0.1" />
<PackageVersion Include="AmLog.Format" Version="1.0.1" />
<PackageReference Include="AmLog.Format" />
paket add AmLog.Format --version 1.0.1
#r "nuget: AmLog.Format, 1.0.1"
#:package AmLog.Format@1.0.1
#addin nuget:?package=AmLog.Format&version=1.0.1
#tool nuget:?package=AmLog.Format&version=1.0.1
AmLog.Format
Библиотека на C# для чтения и записи файлов логов печати в формате .amlog.
Структура решения
| Проект | Назначение |
|---|---|
| AmLog.Format | Основная библиотека: AmLogWriter, AmLogReader, модели разделов, CRC-32C, кодеки, recovery |
| AmLog.Tests | Модульные тесты (xUnit): round-trip, compliance, recovery |
| AmLogTestConsole | Консольный демо-сценарий полной записи и чтения всех разделов |
Описание
Формат .amlog хранит полную информацию о сессии 3D-печати: метаданные, датчики, журналы, аварии, события, метрики слоёв, импульсы, дефекты машинного зрения, параметры лазера и снимки слоёв.
Библиотека рассчитана на:
- потоковую запись без удержания всего файла в памяти;
- произвольный доступ к изображениям без последовательного сканирования;
- явный режим восстановления (
OpenRecovery) для незавершённых или повреждённых файлов; - контроль целостности CRC-32C на блоках, разделах и каталоге;
- самодостаточность файла — каталог датчиков и метаданные внутри META.
Особенности
- Все разделы:
META,SENS,LOGS,ALRM,EVNT,MTRC,PULS,DEFC,LASR,IMGS - Кодеки:
None,Deflate,Zstandard(по умолчанию Zstandard) - CRC-32C (встроенная реализация
CrcHelper, без Crc32.NET) Finalize()обязателен явно —Disposeне финализирует файлAmLogReader.Openтребует финализированный файл; для частичных — толькоOpenRecovery- META обязателен первым; повтор одного типа раздела запрещён
- Прореживание датчиков (
ReadNumericDecimated/ReadSeriesсmaxPoints) без полной материализации серии - Потоковая запись/чтение JPEG в IMGS (
AddImage/OpenImageStreamбез буферизации всего кадра)
Быстрый старт
Запись
using AmLog.Format.Enums;
using AmLog.Format.Sections;
using AmLog.Format.Services.AmLogWriter;
using AmLog.Format.Supported;
var options = new AmLogWriterOptions
{
SessionId = 4821,
WriterVersion = 100,
DefaultCodec = Codec.Zstandard
};
using var writer = AmLogWriter.Create("session.amlog", options);
writer.WriteMeta(meta); // AmLogMeta — обязательный первый раздел
using (var logs = writer.BeginLogs())
logs.AddRecord(new LogRecord(t, 0, LogLevel.Info, LogChannel.Info, "System", "Старт"));
using (var alarms = writer.BeginAlarms())
alarms.AddRecord(...);
using (var events = writer.BeginEvents())
events.AddRecord(...);
using (var metrics = writer.BeginMetrics())
metrics.AddRecord(...);
using (var pulses = writer.BeginPulses())
pulses.AddRecord(...);
using (var defects = writer.BeginDefects())
defects.AddRecord(...);
using (var sensors = writer.BeginSensors(schema)) // SensorSchema
sensors.AddSample(timeUtcMs, layer, numericSpan, logicalSpan);
writer.WriteLaser(laser); // AmLogLaser (parts → regions)
using (var images = writer.BeginImages())
{
using var jpeg = File.OpenRead("layer0.jpg");
images.AddImage(layer: 0, ImagePhase.Applied, jpeg, jpeg.Length);
}
// Обязательно: каталог + футер + флаг завершения в FileHeader
writer.Finalize();
Также доступны AmLogWriter.Create(Stream, options, leaveOpen) и FinalizeAsync.
Чтение (нормальный режим)
using AmLog.Format.Services.AmLogReader;
using var reader = AmLogReader.Open("session.amlog");
Console.WriteLine($"{reader.FormatVersion.Major}.{reader.FormatVersion.Minor}, finalized={reader.IsFinalized}");
AmLogMeta meta = reader.ReadMeta();
var logs = reader.ReadLogs().ToList();
var alarms = reader.ReadAlarms().ToList();
var events = reader.ReadEvents().ToList();
var metrics = reader.ReadMetrics().ToList();
var pulses = reader.ReadPulses().ToList();
var defects = reader.ReadDefects().ToList();
AmLogLaser? laser = reader.ReadLaser();
using (var sensors = reader.OpenSensors())
{
var preamble = sensors.GetPreamble();
var series = sensors.ReadSeries(layerFrom: 0, layerTo: 10, maxPoints: 1000);
var channel = sensors.ReadNumericDecimated("chamberPressure", 0, 10, maxPoints: 200);
}
using (var images = reader.OpenImages())
{
foreach (var key in images.Index)
{
if (images.TryGetImage(key.Layer, key.Phase, out var entry))
{
using var stream = images.OpenImageStream(key.Layer, key.Phase);
// entry.Crc32c, entry.Length, entry.Offset
}
}
}
Режим восстановления
Open не включает recovery автоматически. Если файл не финализирован или повреждён футер/каталог:
using var reader = AmLogReader.OpenRecovery("session.amlog", out AmLogIntegrityReport report);
Console.WriteLine($"finalized={report.IsFinalized}, complete={report.IsComplete}");
Console.WriteLine($"corrupt blocks={report.BlocksCorrupt}, issues={report.Issues.Count}");
// Далее те же ReadMeta / ReadLogs / OpenSensors / … (повреждённые блоки пропускаются)
Формат .amlog
[ FileHeader 64 B ] // magic, версия, flags, sessionId, createdAt, GUID, CRC
[ Section … ]* // META обязателен первым
[ CatalogEntry 48 B ]* // смещения разделов
[ Footer 32 B ] // AMLOGEND + CRC каталога
Каждый раздел:
- SectionHeader (32 B) — тип (
META/SENS/…), кодек, число блоков/записей, преамбула, CRC заголовка - Преамбула (для
SENS,IMGS) — схема каналов / индекс снимков - Блоки —
BlockHeader+ полезная нагрузка (сжатая или нет), CRC от несжатых данных
Флаг завершения (FileHeader.Flags bit 0) выставляется только в Finalize(), после записи каталога и футера. Dispose без Finalize оставляет файл незавершённым — его можно открыть через OpenRecovery.
Поддерживаемые разделы: META, SENS, LOGS, ALRM, EVNT, MTRC, PULS, DEFC, LASR, IMGS.
META (нормативная модель)
AmLogMeta: session, machine, project, operator, sensorCatalog, producedAtUtcMs, producedBy.
SENS
Писатель: BeginSensors(SensorSchema) → AddSample(...).
В блоке: baseTimeUtcMs, timeDelta[R]: uint32, абсолютные layer[R]: int32 и numeric[ch][R]: float32.
Отрицательный timeDelta относительно базы блока — ошибка использования.
Читатель: OpenSensors() → ReadSeries / ReadNumericDecimated / ReadLogical.
LASR
JSON-документ AmLogLaser: parts[] → regions[] (powerW, speedMmS, diameterMm, skywriting).
IMGS
Потоковая запись JPEG; в индексе — абсолютные смещения, длина и CRC-32C каждого снимка.
Ключевые механизмы
| Механизм | Поведение |
|---|---|
| CRC-32C | FileHeader, SectionHeader, BlockHeader, payload, section CRC в каталоге, Directory CRC в Footer (CrcHelper) |
| Сжатие | На уровне раздела; если сжатие не даёт выигрыша — storedSize == rawSize |
| Блоки | Единица восстановления: повреждённый блок пропускается |
| Каталог в конце | Потоковая запись без знания смещений заранее |
| Recovery | Сканирование сигнатур ASEC/ABLK (RecoveryScanner), отчёт AmLogIntegrityReport |
| Изображения | Seek по смещению из индекса; OpenImageStream отдаёт срез потока после проверки CRC |
Системные требования
- .NET 8.0+
- Windows / Linux / macOS
- Зависимость:
ZstdSharp.Port(Zstandard)
Сборка и тесты
dotnet build AmLogViewer.sln
dotnet test --project AmLog.Tests
AmLogTestConsole
Полный сценарий записи всех разделов и чтения с выводом:
dotnet run --project AmLogTestConsole
Файл создаётся в AmLogTestConsole/out/demo-session.amlog (относительно текущей рабочей директории).
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 was computed. 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. |
-
net8.0
- ZstdSharp.Port (>= 0.8.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.