Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2c81758b5 | ||
|
|
6b52a1876f |
@@ -15,9 +15,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const maxSingleFileSize = 10 * 1024 * 1024
|
const maxSingleFileSize = 10 * 1024 * 1024
|
||||||
|
const maxSingleFileSizeLarge = 1024 * 1024 * 1024
|
||||||
const maxZipArchiveSize = 50 * 1024 * 1024
|
const maxZipArchiveSize = 50 * 1024 * 1024
|
||||||
const maxGzipDecompressedSize = 50 * 1024 * 1024
|
const maxGzipDecompressedSize = 50 * 1024 * 1024
|
||||||
|
|
||||||
|
|
||||||
var supportedArchiveExt = map[string]struct{}{
|
var supportedArchiveExt = map[string]struct{}{
|
||||||
".ahs": {},
|
".ahs": {},
|
||||||
".gz": {},
|
".gz": {},
|
||||||
@@ -47,7 +49,7 @@ func ExtractArchive(archivePath string) ([]ExtractedFile, error) {
|
|||||||
|
|
||||||
switch ext {
|
switch ext {
|
||||||
case ".ahs":
|
case ".ahs":
|
||||||
return extractSingleFile(archivePath)
|
return extractSingleFileWithLimit(archivePath, maxSingleFileSizeLarge)
|
||||||
case ".gz", ".tgz":
|
case ".gz", ".tgz":
|
||||||
return extractTarGz(archivePath)
|
return extractTarGz(archivePath)
|
||||||
case ".tar", ".sds":
|
case ".tar", ".sds":
|
||||||
@@ -55,7 +57,7 @@ func ExtractArchive(archivePath string) ([]ExtractedFile, error) {
|
|||||||
case ".zip":
|
case ".zip":
|
||||||
return extractZip(archivePath)
|
return extractZip(archivePath)
|
||||||
case ".txt", ".log":
|
case ".txt", ".log":
|
||||||
return extractSingleFile(archivePath)
|
return extractSingleFileWithLimit(archivePath, maxSingleFileSize)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported archive format: %s", ext)
|
return nil, fmt.Errorf("unsupported archive format: %s", ext)
|
||||||
}
|
}
|
||||||
@@ -70,7 +72,7 @@ func ExtractArchiveFromReader(r io.Reader, filename string) ([]ExtractedFile, er
|
|||||||
|
|
||||||
switch ext {
|
switch ext {
|
||||||
case ".ahs":
|
case ".ahs":
|
||||||
return extractSingleFileFromReader(r, filename)
|
return extractSingleFileFromReaderWithLimit(r, filename, maxSingleFileSizeLarge)
|
||||||
case ".gz", ".tgz":
|
case ".gz", ".tgz":
|
||||||
return extractTarGzFromReader(r, filename)
|
return extractTarGzFromReader(r, filename)
|
||||||
case ".tar", ".sds":
|
case ".tar", ".sds":
|
||||||
@@ -78,7 +80,7 @@ func ExtractArchiveFromReader(r io.Reader, filename string) ([]ExtractedFile, er
|
|||||||
case ".zip":
|
case ".zip":
|
||||||
return extractZipFromReader(r)
|
return extractZipFromReader(r)
|
||||||
case ".txt", ".log":
|
case ".txt", ".log":
|
||||||
return extractSingleFileFromReader(r, filename)
|
return extractSingleFileFromReaderWithLimit(r, filename, maxSingleFileSize)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported archive format: %s", ext)
|
return nil, fmt.Errorf("unsupported archive format: %s", ext)
|
||||||
}
|
}
|
||||||
@@ -337,7 +339,7 @@ func extractZipFromReader(r io.Reader) ([]ExtractedFile, error) {
|
|||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractSingleFile(path string) ([]ExtractedFile, error) {
|
func extractSingleFileWithLimit(path string, limit int64) ([]ExtractedFile, error) {
|
||||||
info, err := os.Stat(path)
|
info, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("stat file: %w", err)
|
return nil, fmt.Errorf("stat file: %w", err)
|
||||||
@@ -348,7 +350,7 @@ func extractSingleFile(path string) ([]ExtractedFile, error) {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
files, err := extractSingleFileFromReader(f, filepath.Base(path))
|
files, err := extractSingleFileFromReaderWithLimit(f, filepath.Base(path), limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -358,14 +360,14 @@ func extractSingleFile(path string) ([]ExtractedFile, error) {
|
|||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractSingleFileFromReader(r io.Reader, filename string) ([]ExtractedFile, error) {
|
func extractSingleFileFromReaderWithLimit(r io.Reader, filename string, limit int64) ([]ExtractedFile, error) {
|
||||||
content, err := io.ReadAll(io.LimitReader(r, maxSingleFileSize+1))
|
content, err := io.ReadAll(io.LimitReader(r, limit+1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read file content: %w", err)
|
return nil, fmt.Errorf("read file content: %w", err)
|
||||||
}
|
}
|
||||||
truncated := len(content) > maxSingleFileSize
|
truncated := int64(len(content)) > limit
|
||||||
if truncated {
|
if truncated {
|
||||||
content = content[:maxSingleFileSize]
|
content = content[:limit]
|
||||||
}
|
}
|
||||||
|
|
||||||
file := ExtractedFile{
|
file := ExtractedFile{
|
||||||
@@ -376,7 +378,7 @@ func extractSingleFileFromReader(r io.Reader, filename string) ([]ExtractedFile,
|
|||||||
file.Truncated = true
|
file.Truncated = true
|
||||||
file.TruncatedMessage = fmt.Sprintf(
|
file.TruncatedMessage = fmt.Sprintf(
|
||||||
"file exceeded %d bytes and was truncated",
|
"file exceeded %d bytes and was truncated",
|
||||||
maxSingleFileSize,
|
limit,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
60
releases/v1.22/RELEASE_NOTES.md
Normal file
60
releases/v1.22/RELEASE_NOTES.md
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# logpile v1.22
|
||||||
|
|
||||||
|
Дата релиза: 2026-06-19
|
||||||
|
Тег: `v1.22`
|
||||||
|
|
||||||
|
## Что нового
|
||||||
|
|
||||||
|
### HPE iLO AHS — новый парсер
|
||||||
|
|
||||||
|
Добавлена поддержка файлов `*.ahs` (Active Health System), экспортируемых
|
||||||
|
из веб-интерфейса iLO. Парсер извлекает:
|
||||||
|
|
||||||
|
- **Инвентарь оборудования**: плата, процессоры, память, диски, сетевые
|
||||||
|
адаптеры, блоки питания, backplane, RAID-контроллеры.
|
||||||
|
- **Прошивки**: iLO, System ROM, SPS, TPM, SPLD, контроллеры, NIC, backplane —
|
||||||
|
из основного бинарного контейнера и XML-сертификата `bcert.pkg`.
|
||||||
|
- **События**: разбор `.zbb`-файлов с журналом iLO; определение типа и
|
||||||
|
серьёзности по тексту сообщения; очистка однобайтовых frame-сепараторов
|
||||||
|
из концов строк.
|
||||||
|
- **Устойчивость к битым файлам**: если последняя запись в AHS-контейнере
|
||||||
|
обрезана (объявленный размер выходит за границу файла), парсер обрабатывает
|
||||||
|
данные частично вместо возврата ошибки.
|
||||||
|
- Добавлено распознавание модельного ряда **Alletra Storage Server** (ранее
|
||||||
|
`ProductName` оставался пустым).
|
||||||
|
|
||||||
|
### Экспорт логов в CSV («Logs Export»)
|
||||||
|
|
||||||
|
Новая кнопка «**Logs Export**» в шапке интерфейса выгружает все
|
||||||
|
распознанные события (без какой-либо фильтрации) в CSV-файл:
|
||||||
|
|
||||||
|
- Разделитель — точка с запятой (`;`), кодировка — UTF-8 с BOM.
|
||||||
|
- Файл открывается в Excel без дополнительных настроек импорта.
|
||||||
|
- Колонки: `timestamp`, `source`, `severity`, `sensor_type`, `sensor_name`,
|
||||||
|
`event_type`, `id`, `description`, `raw_data`.
|
||||||
|
|
||||||
|
Кнопка «PDF» удалена.
|
||||||
|
|
||||||
|
### Исправления в Reanimator-экспорте
|
||||||
|
|
||||||
|
- `event_logs` в JSON-экспорте Reanimator больше не оказывается пустым для
|
||||||
|
HPE iLO AHS: источник `"HPE iLO"` теперь корректно нормализуется в `"bmc"`.
|
||||||
|
|
||||||
|
### Исправления chart viewer
|
||||||
|
|
||||||
|
- JavaScript `view.js` не загружался в LOGPile из-за отсутствия перезаписи
|
||||||
|
пути `/static/view.js` → `/chart/static/view.js`. Исправлено; фильтры
|
||||||
|
по колонкам в таблицах теперь работают.
|
||||||
|
- Субмодуль chart обновлён до **v2.7**: фильтры вынесены в отдельную строку
|
||||||
|
под заголовком, исправлена минимальная ширина колонок.
|
||||||
|
|
||||||
|
### Обновления зависимостей
|
||||||
|
|
||||||
|
- **pci.ids** (база PCI-устройств) обновлена. Коллектор скорректирован под
|
||||||
|
переименование `0x8086:0x28c0`: `"Volume Management Device NVMe RAID
|
||||||
|
Controller"` → `"Volume Management Device (VMD)"`.
|
||||||
|
|
||||||
|
## Запуск на macOS
|
||||||
|
|
||||||
|
Снимите карантинный атрибут через терминал: `xattr -d com.apple.quarantine /path/to/logpile-darwin-arm64`
|
||||||
|
После этого бинарник запустится без предупреждения Gatekeeper.
|
||||||
Reference in New Issue
Block a user