отображать только части строк из файла журнала в реальном времени

отображать только части строк из файла журнала в реальном времени

У нас есть файл журнала, который я часто просматриваю в режиме реального времени с помощью tail и использую grep для фильтрации интересующих меня строк. Однако строки содержат много данных, которые мне не всегда интересны, но мне было сложно их анализировать, поэтому я вижу только те части строки, которые мне нужны. Формат каждой записи строки — это в основном список тегов и данных (иногда содержащих пробелы), окруженных кавычками. Вот несколько примеров (очищенных) строк журнала:

2017:11:29-11:29:56 filter-1 httpproxy[3194]: id="0001" severity="info" sys="SecureWeb" sub="http" name="http access" action="pass" method="CONNECT" srcip="10.11.12.13" dstip="14.3.1.4" user="" group="" ad_domain="" statuscode="200" cached="0" profile="REF_HttPro1234 (Campus2)" filteraction="REF_HttStu (Allow Policy)" size="6518" request="0x915a3e00" url="https://website.net/" referer="" error="" authtime="0" dnstime="1" cattime="73" avscantime="0" fullreqtime="61576999" device="0" auth="6" ua="" exceptions="" category="9998" reputation="unverified" categoryname="Uncategorized" country="United States" application="krux" app-id="826"
2017:11:29-11:29:56 filter-1 httpproxy[3194]: id="0001" severity="info" sys="SecureWeb" sub="http" name="http access" action="pass" method="GET" srcip="10.13.14.15" dstip="154.6.75.10" user="" group="" ad_domain="" statuscode="200" cached="0" profile="REF_HttPro1235 (Campus1)" filteraction="REF_HttStu (Allow Policy)" size="3161" request="0x6b4d5610" url="http://host.com/mini_banner.png" referer="http://www.web.com/computers.htm" error="" authtime="0" dnstime="0" cattime="64" avscantime="848" fullreqtime="50046" device="0" auth="6" ua="Mozilla/5.0 (X11; CrOS x86_64 9765.85.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.123 Safari/537.36" exceptions="" category="111" reputation="trusted" categoryname="Education/Reference" sandbox="-" content-type="image/png"

Стоит отметить, что не все теги присутствуют в каждой строке. Например, application и app-id присутствуют в первой строке, но не во второй.

Используя строки выше в качестве примера ввода, пример того, что я хотел бы иметь в качестве вывода, это показывать только теги srcip, categoryname и url в указанном порядке. Желаемый вывод будет выглядеть примерно так:

10.11.12.13 Uncategorized https://website.net/
10.13.14.15 Education/Reference http://host.com/mini_banner.png

Я ищу решение, которое можно легко адаптировать, чтобы я мог «на лету» настраивать отображаемые теги.

решение1

Ваши данные хорошо структурированы, так какключ="значение", поэтому вы можете написать небольшой скрипт оболочки с использованием gnu awk, который принимает в качестве аргумента список имен ключей и просто выводит эти значения. Например, myscript:

#!/bin/bash
awk -v lhs="$*" '
BEGIN{  FPAT = "[a-z-]*=\"[^\"]*\""
        nwant = split(lhs,want)
}
{       for(i=1;i<=NF;i++){
            start = match($i,/([a-z-]*)="([^"]*)"/,a)
            key[a[1]] = a[2]
        }
        for(i=1;i<=nwant;i++){printf "%s ",key[want[i]]; key[want[i]] = ""}
        printf "\n"
}'

который вы вызываете как myscript srcip categoryname url. Это устанавливает переменную awk lhsдля аргументов как одну строку, которые в начале разбиваются на массив want. Строки разбиваются awk на поля, соответствующие шаблонуключ="значение"с помощью встроенной FPATпеременной.

В каждой строке, для каждого поля мы разделяем его на match()2 захваченные группы, для ключа и для части в двойных кавычках. Они помещаются awk в массив a, и мы сохраняем их в ассоциативном массиве, keyиндексируемом строкой ключа.

Затем для каждого нужного ключа мы печатаем значение и очищаем его для следующей строки (в случае, если в этой строке нет этого ключа). Очевидно, это предполагает, что все данные имеют требуемую структуру и потребуются изменения для обработки (") внутри значения или ключей с неалфавитными символами.


Версии gnu awk (gawk) до 4.0 не имеют FPATвстроенной функции для разбиения строки на поля, соответствующие шаблону, поэтому вам придется сделать это самостоятельно:

#!/bin/bash
awk -v lhs="$*" '
BEGIN{ nwant = split(lhs,want) }
{       input = $0
        while(match(input,"[a-z-]*=\"[^\"]*\"")>0){
            field = substr(input,RSTART,RLENGTH)
            input = substr(input,RSTART+RLENGTH)
            start = match(field,/([a-z-]*)="([^"]*)"/,a)
            key[a[1]] = a[2]
        }
        for(i=1;i<=nwant;i++){printf "%s ",key[want[i]]; key[want[i]] = ""}
        printf "\n"
}'

Разумеется, можно объединить два вызова сопоставления в один, но здесь видна разница с оригиналом.

решение2

Использование (совместимого с POSIX) sed...

sed 's/.* srcip="\([^"]*\)" .* url="\([^"]*\)" .* categoryname="\([^"]*\)" .*/\1 \3 \2/' logfile

Ничего особенного, просто найдите ключи и заключите значения в скобки, \(..\)что позволит использовать их в качестве обратных ссылок. Затем мы заменяем строку только обратными ссылками, разделенными пробелами, упорядоченными по вашему требованию: \1 \3 \2.

Выход:

10.11.12.13 Uncategorized https://website.net/
10.13.14.15 Education/Reference http://host.com/mini_banner.png

Если в журналах содержатся строки, не имеющие всех этих ключей, то вы можете использовать:

sed -n 's/.* srcip="\([^"]*\)" .* url="\([^"]*\)" .* categoryname="\([^"]*\)" .*/\1 \3 \2/p' logfile

Будут напечатаны только те строки, которые соответствуют шаблону.

И, конечно, если вы хотите использовать их в потоковом режиме, просто удалите имя файла и сделайте[something sending logs to stdout] | sed ...

Связанный контент