Сразу уточню: у задачи есть множество других решений - увеличение лимита памяти для скрипта, использование MongoDB, исползование другого синтаксиса записей и так далее. По различным причинам эти варианты не подходят. Кроме того, тут присутствует спортивный интерес.
Итак: в одном проекте логи храфнтся в виде json записей в файлах. Такое решение было принято для упрощения сохранения и извлечения информационных данных, которые могут быть и массивами и объектами.
Естественно возникла проблема с использованием json_decode: даже небольшой лог файл (10mb) занимает больше 128mb памяти (в пике) для расшифровки. Весь файл необходимо читать целиком, т.к. в инструменте анализа преистствуют функции сортиировки и фильтрации записей.
Что представляет из себя лог файл:
{
"timestamp":"2014-03-04T13:16:13+01:00",
"message":"start exec test",
"priority":1,
"priorityName":"ALERT"
},{
"timestamp":"2014-03-04T13:16:13+01:00",
"message":"got logname",
"priority":2,
"priorityName":"CRIT",
"info":"cronLogTest"
},{
"timestamp":"2014-03-04T13:16:14+01:00",
"message":"Some additional info",
"priority":7,
"priorityName":"DEBUG",
"info":[
{
"Type":"rec",
"Name":"name",
"Description":"desc",
"Lang":"EN"
},{
"Type":"rec",
"Name":"name2",
"Description":"desc2",
"Lang":"DE"
}
]
},{
"timestamp":"2014-03-04T13:16:15+01:00",
"message":"stop exec test",
"priority":1,
"priorityName":"ALERT"
},
Отсутствие контейнера гарантирует целостность файла во время крэша, контейнер добавляется непосредствено перед парсингом.
Иатк, первое, что приходит в голову - парсить только верхние элементы: они все обладают одинаковыми полями и их парсинг займёт меньше памяти чем рекурсивный обход всей структуры с помощью json_decode (или другого парсера, которые были протестированы и не показали большую эффективность) и этих полей будет достаточно для сортировки и фильтрации. Вложенные записи могут быть декодированны уже непосредственно перед отдачей информации на фронтенд (используется пагинатор, так-что нет необходимости декодировать сразу всю информацию).
Итак, 2 вопроса:
1. Как бы вы подошли к вопросу ручного парсинга подобной структуры? У меня есть идеи алгоритмов, но меня интересует взгляд со стороны. Естественно критичным ресурсом является потребление памяти (скорость на втором плане).
2. Считаете ли вы такой вариант приемлимым? Изменение формата или хранилища логов не годится из-за необходимости чтения большого количества уже созданных логов на лайве - может есть другой вариант, который я не заметил?