LINUX.ORG.RU
ФорумAdmin

Парсинг логов

 , , ,


0

1

Привет!

Очень нужна помощь. Есть необходимость для обучения - отбирать логи за определенный день и записывать их в файл с датой (например, 2022-07-18.txt). Нет понимания - как отбирать все файлы за конкретный день и как автоматически создавать файл с логами.

Подскажите, какие у меня есть варианты и куда можно посмотреть для решения этой задачи?

Всех заранее благодарю!

cat /var/log/file | grep $(date "+%Y-%m-%d") >> $(date "+%Y-%m-%d").txt

+%Y-%m-%d - заменить на формат даты. /var/log/file - на файл с логами.

Clockwork ★★★★★
()
Последнее исправление: Clockwork (всего исправлений: 1)

Подскажите, какие у меня есть варианты

Вариантов миллиард. Вплоть до читерского

journalctl -S 2022-07-18 -U 2022-07-19

gremlin_the_red ★★★★★
()

Нет понимания - как отбирать все файлы за конкретный день

Отбирать надо файлы или строчки в них?

отбирать логи за определенный день и записывать их в файл с датой

Что записывать? Имена найденных файлов или строки из них?

Подскажите, какие у меня есть варианты

Я бы писал прогу на Си. Для поиска файлов - man readdir, для чтения - man fgets, для парсинга даты своя несложная функция.

Всякие grep и прочая скриптота годится для разового использования из командной строки «прямо сейчас», а для штатного решения задачи надолго оно слишком тормозное, лучше писать специализированное.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

Я бы писал прогу на Си.

Может, топикстартеру надо прочесть лог из сотни строчек раз в день. Тогда grep хватит с избытком.

x22 ★★
()
Ответ на: комментарий от x22

Грепа и на миллион строк хватит с избытком.

vbr ★★★★★
()
Ответ на: комментарий от x22

grep не хватит превратить Jan в 01 и добавить год из даты модификации файла (а на самом деле чуть сложнее) в дату в ответе. Хотя эти операции конечно тоже можно сделать скриптами но смотреться будет некрасиво.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Всякие grep и прочая скриптота годится для разового использования из командной строки «прямо сейчас», а для штатного решения задачи надолго оно слишком тормозное, лучше писать специализированное.

Очень любопытная точка зрения

pihter ★★★★★
()
Ответ на: комментарий от firkax

смотреться будет некрасиво

Красивее некуда. На си будет много лоно и ошибкоопасно на ровном месте

pihter ★★★★★
()
Ответ на: комментарий от pihter

А если у него линукс, а не винда, рядящаяся под линукс?)

Ну это пусть ТС уточнит, что у него, чего гадать то. У меня fedora34 текстовых логов очень мало, все в основном в journalctl

alex_sim ★★★★
()
Ответ на: комментарий от alex_sim

Ну это пусть ТС уточнит, что у него, чего гадать то. У меня fedora34 текстовых логов очень мало, все в основном в journalctl

У меня Ubuntu 20.04.3

gattyoppa
() автор топика
Ответ на: комментарий от firkax

grep не хватит превратить Jan в 01 ...

А шо таки grep уже один во всем юниксе?

Написать скриптик вроде такого:

#!/bin/sh

ms_1=Jan; ... ms_7=Jul; ... ms_12=Dec;

mn=7; d=18

eval m=\${ms_${mn}}
year=`stat --format=%z logfile | sed 's,-.*$,,'`
test $mn -lt 10 && mn=0$mn

grep -E «${m}[ ]+${d}[ ]+[0-9]{2}:[0-9]{2}:[0-9]{2}» logfile > ${year}-${mn}-${d}.txt

x22 ★★
()
Ответ на: комментарий от alex_sim

Да это я так «умело» хохмю, мол, системдэ - виндоус вей

pihter ★★★★★
()
Ответ на: комментарий от x22

Круто, и если надо собрать логи за несколько дней - весь исходник надо будет пролистывать каждый раз заново. А year я не случайно указал что на самом деле сложнее. Если дата у лога 5 января 2022 и в нём есть запись за 5 декабря, то год у неё - не больше чем 2021.

firkax ★★★★★
()
Ответ на: комментарий от firkax

grep не хватит превратить Jan в 01 и добавить год из даты модификации файла (а на самом деле чуть сложнее) в дату в ответе.

А зачем превращать, если можно получить вторую переменную в нужном формате? Одну брать для грепа, вторую для названия. Нельзя?

Clockwork ★★★★★
()
Ответ на: комментарий от firkax

Круто, и если надо собрать логи за несколько дней - весь исходник надо будет пролистывать каждый раз заново.

Какого размера лог? Если до ~10^5 строк, то можно не думать про перечитывать.

Если дата у лога 5 января 2022 и в нём есть запись за 5 декабря, то год у неё - не больше чем 2021.

Проще в timestamp в логе добавить год к «Month Day HH:MM:SS». Тогда можно написать в лоб:

#!/bin/sh

mn_Jan=01; ... mn_Jul=07; ... mn_Dec=12

while read year month day hms s ; do 
 eval mn=\${mn_${month}}
 echo $year $month $day $hms $s >> ${year}-${mn}-${day}.txt
done < logfile

Букв всяко меньше, чем на C.

x22 ★★
()
Ответ на: комментарий от x22

Какого размера лог? Если до ~10^5 строк, то можно не думать про перечитывать.

Разумеется, если там какая-то мелочь, и она гарантированно всегда будет мелочью, можно делать и так. У меня раньше тоже были всякие скрипты с grep-ами для фильтрации логов, написанные на скорую руку когда прям сейчас надо было. Со временем их тормознутость и негибкость бесила всё больше, переделал всё на нормальный код и больше по-плохому не делаю.

Проще в timestamp в логе добавить год

Тогда уж проще сразу лог писать в YYYY-MM-DD HH:MM:SS и в нужный файл (если мы можем им управлять). Но по условию задачи я так понял что лог есть в том (неудобном) формате как есть, и надо сделать из него удобный. Впрочем там весьма мутное описание, может автор и уточнит что.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от firkax

Автору набросали достаточно примеров простой обработки текста в юниксе. Будут вопросы – можно дальше подсказывать.

x22 ★★
()
Ответ на: комментарий от anc

Не пиши ерунду. Всё (кроме редкой экзотики) в итоге написано либо на си, либо на ассемблере, но это не значит что тот же пхп (написанный на си) быстрый. И твой любимый VBS тоже написан на си.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от firkax

Не пиши ерунду.

Вы первый начали. Не умение применять инструмент, не означает, что инструмент негодный.

anc ★★★★★
()
Ответ на: комментарий от anc

Избыточно.

Нет. А вот ваш вариант. 1. забагован «из каробки».

Ебстественно. shell '...' не переварит.

2. Избыточен.

Пишите свой, топикстартеру будет полезно.

x22 ★★
()
Ответ на: комментарий от x22

Ебстественно. shell '...' не переварит.

Не в троеточии дело.

Пишите свой, топикстартеру будет полезно.

Я указал на недостатки вашего варианта. Но похоже вы восприняли критику в варианте «УМВР, ты ничего не понимаешь...»
ЗЫ Ааа, ещё один баг обнаружил. :) Посмотрите на вашу последнюю строку.

anc ★★★★★
()
Последнее исправление: anc (всего исправлений: 1)
Ответ на: комментарий от anc

Не в троеточии дело.

Никто не сомневается. Сделайте разбор ошибок, пишите правильный вариант, все скажут спасибо.

x22 ★★
()
Ответ на: комментарий от firkax

Когда приведете сравнение хотя бы на двух, трех синтетических тестах, тогда и заходите.

ЗЫ Я знаю, что ваше предложение не лишено смысла, как «сферическое». В смысле, что оно имеет место быть правильным в определенных ситуациях. Но это не значит, что его надо продвигать абсолютно во все ситуации. Беря молоток в руки, не надо на всё что вас окружает смотреть как на гвозди.

anc ★★★★★
()
Ответ на: комментарий от anc

Когда приведете сравнение хотя бы на двух, трех синтетических тестах, тогда и заходите.

Два теста мне лень делать, сделал один, самый тривиальный.

Взял много логов из десктопного /var/log (cat | gunzip архивные), повторил, вышел входной файл на 800мбайт. Положил его в tmpfs (иначе жёсткий диск портит чистоту теста), запустил такие команды (см.ниже).

Разница в скорости (user time) - в 6 раз (grep 1.48 сек, нормальный сканер 0.24 сек). Если даже добавить system time которое там было одинаковое в полсекунды - получается разница в скорости в 3 раза (0.7 против 2.0). Если добавить побольше парсерной логики - разница, очевидно, станет ещё больше, на особо сложных случаях может и в 100 раз. А если ещё вызовы всяких date и прочей чуши в баш-подпроцессах заменить на тупо выполняющиеся мгновенно функции, например для конвертации плохого формата даты в хороший - то даже не знаю.

gcc -O2 slow_grep_example.c
time grep "^Jun" < log0 > log1g
time ./a.out < log0 > log1m
diff log1g log1m

slow_grep_example.c:

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

#define READ_BUF_SIZE 131072
/*#define USE_FWRITE_BUF_SIZE 4096*/
/*#define MAX_READ 98304*/

static char buf[READ_BUF_SIZE];
static size_t bsz, pos;
static int state;

static int write_all(char const *b, size_t n) {
  size_t c;
  ssize_t r;
  while(c=n) {
/*    if(c>8192) c = 8192;*/
    while(((ssize_t)c)<=0) c/=2;
    while((r = write(1, b, c))<0) if(errno!=EINTR) return -1;
    /* assert(r>0 && c>=(size_t)r); */
    b += r; n -= r;
  }
  return 0;
}
#ifdef USE_FWRITE_BUF_SIZE
#define write_all(b,n) fwrite(b,1,n,stdout)
#endif

int main(void) {
  ssize_t rsz;
  size_t n;
  char *b;
  int nextstate;
#ifdef USE_FWRITE_BUF_SIZE
  static char ob[USE_FWRITE_BUF_SIZE];
  setbuffer(stdout,ob,sizeof(ob));
#endif

  while(1) {
    if(pos && bsz-pos<100) {
      if(bsz -= pos) bcopy(buf+pos, buf, bsz);
      pos = 0;
    }
    n = sizeof(buf)-bsz;
#ifdef MAX_READ
    if(n>MAX_READ) n = MAX_READ;
#endif
    while((rsz=read(0, buf+bsz, n))<0) if(errno!=EINTR) { fprintf(stderr, "read error %d (%s)\n", errno, strerror(errno)); break; }
    if(rsz<=0) break;
    bsz += rsz;
    if(!state) {
      if(bsz-pos<3) continue;
      if(buf[pos]=='J' && buf[pos+1]=='u' && buf[pos+2]=='n') state = 1;
      else state = 2;
    }
loop:
    b = memchr(buf+pos, '\n', bsz-pos);
again:
    if(!b) {
      if(state==1 && write_all(buf+pos, bsz-pos)<0) { fprintf(stderr, "write error %d (%s)\n", errno, strerror(errno)); break; }
      bsz = pos = 0; continue;
    }
    n = b+1-buf;
    if(bsz-n<3) nextstate = 0;
    else if(buf[n]=='J' && buf[n+1]=='u' && buf[n+2]=='n') nextstate = 1;
    else nextstate = 2;
#ifndef USE_FWRITE_BUF_SIZE
    if(nextstate==state) { b = memchr(buf+n, '\n', bsz-n); goto again; }
#endif
    if(state==1 && write_all(buf+pos, n-pos)<0) { fprintf(stderr, "write error %d (%s)\n", errno, strerror(errno)); break; }
    pos = n; state = nextstate;
    if(state) goto loop;
  }
  return rsz?-1:0;
}

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от firkax

Судя по всему, вы пока остановились на «скорости». Как сравните результаты, расскажите обязательно.

anc ★★★★★
()
Ответ на: комментарий от anc

Читать учись, результаты - разница в 6 раз и не в пользу grep-а. И пойми уже, что инструмент общего назначения почти всегда будет хуже, чем узкоспециализированный под задачу. У узкоспециализированного минус только один - его надо каждый раз делать заново, но если он делается на годы использования то это не проблема.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Ну т.е. результаты всё ещё не сравнили. Для непонятливых поясняю. «результаты» - это то что вы получили в результате работы программы, а не как она быстро или медленно, со свистелками или без, работала.

anc ★★★★★
()
Последнее исправление: anc (всего исправлений: 1)
Ответ на: комментарий от anc

Для непонятливых поясняю.

Для не умеющих нормально читать предлагаю прочесть моё сообщение в третий раз. Там даже diff вставлен для проверки - результаты побайтово одинаковые. Да и перевод темы с тормознутости grep-а на подозрения в каких-то багах в моём коде с твоей стороны выглядит крайне убого. Просто признай что твоя любимая скриптота тормозит, и всё.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от anc

Какая разница? Devuan 4 ( = Debian 11), amd64. Скомпилируй исходник у себя и увидишь то же самое.

firkax ★★★★★
()

gattyoppa, вы бы показали кусок лога. Тогда вам рабочий скриптик набросают.

x22 ★★
()
Ответ на: комментарий от x22

Вы серьезно не видите в чем проблема? Оно же просто в глаза кричит.

anc ★★★★★
()
Ответ на: комментарий от firkax

Я в СИсяшке не разбираюсь. Обьяснишь всё, что в slow_grep_example.c ? Потому что на колупание и компиляцию я однозначно больше времени потрачу, чем на однострочник с грепом.

Но спорить не буду, что выполнение грепа – это не быстро.

Pinux001
()
Ответ на: комментарий от Pinux001

Ну так в том его и плюс - его можно сделать быстро прямо сейчас. Когда он нужен 1 раз и время на разработку конкурирует с временем на выполнение. А когда он на регулярной основе в проде используется как часть рабочего процесса - хорошо бы оптимизировать, если не сам так поставить задачу программисту.

firkax ★★★★★
()
Ответ на: комментарий от firkax

… Взял много логов из десктопного /var/log (cat | gunzip архивные), повторил, вышел входной файл на 800мбайт. Положил его в tmpfs (иначе жёсткий диск портит чистоту теста), запустил такие команды (см.ниже). Разница в скорости (user time) - в 6 раз (grep 1.48 сек, нормальный сканер 0.24 сек).

GNU grep, похоже, построчно читает ввод через fgets(). На tmpfs время чтения файла ~100 Mb со строками < 1024b через fgets() и проверкой первых нескольких символов совпадает с точностью ~10% со временем обработки того же grep -E ‘^…’.

x22 ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.