Estamos a desenvolver a interface máis cómoda do mundo* para ver rexistros

Estamos a desenvolver a interface máis cómoda do mundo* para ver rexistros Se algunha vez utilizou interfaces web para ver rexistros, probablemente teña notado como, por regra xeral, estas interfaces son engorrosas e (moitas veces) non moi cómodas e sensibles. Algúns podes afacerte, algúns son absolutamente terribles, pero paréceme que a razón de todos os problemas é que abordamos a tarefa de ver os rexistros de forma incorrecta: tentamos crear unha interface web onde se poña a CLI (interface de liña de comandos). funciona mellor. Persoalmente, estou moi cómodo traballando con tail, grep, awk e outros e, polo tanto, para min a interface ideal para traballar con rexistros sería algo semellante a tail e grep, pero que tamén se podería usar para ler rexistros que proviñan de moitos servidores. Iso é, por suposto, lelos desde ClickHouse!

*segundo a opinión persoal do usuario de habra es xenial

Coñece logscli

Non se me ocorreu un nome para a miña interface e, para ser honesto, máis ben existe en forma de prototipo, pero se queres ver inmediatamente o código fonte, benvido: https://github.com/YuriyNasretdinov/logscli (350 liñas do código Go seleccionado).

Capacidades

O meu obxectivo era facer unha interface que lles parecese familiar a aqueles que estean afeitos a tail/grep, é dicir, soportar as seguintes cousas:

  1. Ver todos os rexistros, sen filtrar.
  2. Deixar liñas que conteñan unha subcadea fixa (flag -F у grep).
  3. Deixa liñas que coincidan coa expresión regular (bandeira -E у grep).
  4. Por defecto, a visualización faise en orde cronolóxica inversa, xa que os rexistros máis recentes adoitan ser de interese primeiro.
  5. Mostra o contexto ao lado de cada liña (opcións -A, -B и -C у grep, imprimindo N liñas antes, despois e arredor de cada liña coincidente, respectivamente).
  6. Consulta os rexistros entrantes en tempo real, con ou sen filtrado (esencialmente tail -f | grep).
  7. A interface debe ser compatible con less, head, tail e outros - por defecto, os resultados deben ser devoltos sen restricións sobre o seu número; as liñas imprímense como un fluxo sempre que o usuario estea interesado en recibilas; sinal SIGPIPE debería interromper silenciosamente a transmisión do rexistro, tal e como fan tail, grep e outras utilidades de UNIX.

Implantación

Asumirei que xa sabes como entregar rexistros a ClickHouse. Se non, recoméndoo probalo LSD и gatinhoE este artigo sobre a entrega de rexistros.

Primeiro cómpre decidir o esquema base. Dado que normalmente queres recibir rexistros ordenados por tempo, parece lóxico almacenalos así. Se hai moitas categorías de rexistro e todas son do mesmo tipo, podes facer unha categoría de rexistro como a primeira columna da clave principal; isto permitirache ter unha táboa en lugar de varias, o que será unha gran vantaxe cando inserindo en ClickHouse (en servidores con discos duros, recoméndase inserir datos non máis de ~1 veces por segundo para todo o servidor).

É dicir, necesitamos aproximadamente o seguinte esquema de táboa:

CREATE TABLE logs(
    category LowCardinality(String), -- категория логов (опционально)
    time DateTime, -- время события
    millis UInt16, -- миллисекунды (могут быть и микросекунды, и т.д.): рекомендуется хранить, если событий много, чтобы было легче различать события между собой
    ..., -- ваши собственные поля, например имя сервера, уровень логирования, и так далее
    message String -- текст сообщения
) ENGINE=MergeTree()
ORDER BY (category, time, millis)

Desafortunadamente, non puiden atopar inmediatamente fontes abertas con rexistros realistas que puidese coller e descargar, polo que tomei isto como exemplo. comentarios de produtos de Amazon antes de 2015. Por suposto, a súa estrutura non é exactamente a mesma que a dos rexistros de texto, pero para fins ilustrativos isto non é importante.

instrucións para cargar comentarios de Amazon en ClickHouse

Imos crear unha táboa:

CREATE TABLE amazon(
   review_date Date,
   time DateTime DEFAULT toDateTime(toUInt32(review_date) * 86400 + rand() % 86400),
   millis UInt16 DEFAULT rand() % 1000,
   marketplace LowCardinality(String),
   customer_id Int64,
   review_id String,
   product_id LowCardinality(String),
   product_parent Int64,
   product_title String,
   product_category LowCardinality(String),
   star_rating UInt8,
   helpful_votes UInt32,
   total_votes UInt32,
   vine FixedString(1),
   verified_purchase FixedString(1),
   review_headline String,
   review_body String
)
ENGINE=MergeTree()
ORDER BY (time, millis)
SETTINGS index_granularity=8192

No conxunto de datos de Amazon só hai unha data para unha revisión, pero non hai unha hora exacta, así que enchemos estes datos cun aleatorio.

Non tes que descargar todos os ficheiros tsv e limitarte aos primeiros ~ 10-20 para obter un conxunto de datos bastante grande que non encaixará en 16 GB de RAM. Para cargar ficheiros TSV usei o seguinte comando:

for i in *.tsv; do
    echo $i;
    tail -n +2 $i | pv |
    clickhouse-client --input_format_allow_errors_ratio 0.5 --query='INSERT INTO amazon(marketplace,customer_id,review_id,product_id,product_parent,product_title,product_category,star_rating,helpful_votes,total_votes,vine,verified_purchase,review_headline,review_body,review_date) FORMAT TabSeparated'
done

Nun disco persistente estándar (que é un HDD) en Google Cloud cun tamaño de 1000 GB (tomei este tamaño principalmente para que a velocidade fose un pouco maior, aínda que quizais un SSD do tamaño necesario tería sido máis barato) a subida. a velocidade foi de aproximadamente ~ 75 MB/s en 4 núcleos.

  • Debo facer unha reserva porque traballo en Google, pero usei unha conta persoal e este artigo non ten nada que ver co meu traballo na empresa

Producirei todas as ilustracións con este conxunto de datos en particular, xa que isto é todo o que tiña a man.

Mostra o progreso da dixitalización de datos

Dado que en ClickHouse faremos unha exploración completa nunha táboa con rexistros, e esta operación pode levar moito tempo e pode que non produza ningún resultado durante moito tempo se se atopan poucas coincidencias, é recomendable poder mostrar o progreso da consulta ata que se reciban as primeiras filas co resultado. Para iso, hai un parámetro na interface HTTP que che permite enviar o progreso nas cabeceiras HTTP: send_progress_in_http_headers=1. Desafortunadamente, a biblioteca Go estándar non pode ler as cabeceiras mentres se reciben, pero ClickHouse admite a interface HTTP 1.0 (que non debe confundirse coa 1.1), polo que pode abrir unha conexión TCP sen procesar a ClickHouse e enviala alí. GET /?query=... HTTP/1.0nn e recibe as cabeceiras e o corpo da resposta sen ningún escape nin cifrado, polo que neste caso nin sequera necesitamos usar a biblioteca estándar.

Rexistros de streaming desde ClickHouse

ClickHouse tivo unha optimización para consultas con ORDER BY durante un tempo relativamente longo (desde 2019?), polo que unha consulta como

SELECT time, millis, message
FROM logs
WHERE message LIKE '%something%'
ORDER BY time DESC, millis DESC

Inmediatamente comezará a devolver liñas que teñan a subcadea "algo" na súa mensaxe, sen esperar a que remate a exploración.

Ademais, sería moi conveniente que o propio ClickHouse cancelase a solicitude cando se pechou a conexión, pero este non é o comportamento predeterminado. A cancelación automática da solicitude pódese activar mediante a opción cancel_http_readonly_queries_on_client_close=1.

Manexo correcto de SIGPIPE en Go

Cando executas, por exemplo, o comando some_cmd | head -n 10, exactamente como o comando some_cmd detén a execución cando head restaron 10 liñas? A resposta é sinxela: cando head remata, o tubo péchase e o stdout do comando some_cmd comeza a apuntar, condicionalmente, "a ningunha parte". Cando some_cmd tenta escribir nun tubo pechado, recibe un sinal SIGPIPE, que finaliza silenciosamente o programa por defecto.

En Go tamén ocorre por defecto, pero o controlador de sinal SIGPIPE tamén imprime "signal: SIGPIPE" ou unha mensaxe similar ao final, e para borrar esta mensaxe só necesitamos manexar SIGPIPE como queremos, é dicir, en silencio. saída:

ch := make(chan os.Signal)
signal.Notify(ch, syscall.SIGPIPE)
go func() {
    <-ch
    os.Exit(0)
}()

Mostra o contexto da mensaxe

A miúdo quere ver o contexto no que se produciu algún erro (por exemplo, que solicitude causou pánico ou que problemas relacionados eran visibles antes do accidente) e grep Isto faise usando as opcións -A, -B e -C, que mostran o número especificado de liñas despois, antes e arredor da mensaxe, respectivamente.

Desafortunadamente, non atopei un xeito sinxelo de facer o mesmo en ClickHouse, polo que para mostrar o contexto, envíase unha solicitude adicional como esta a cada liña do resultado (os detalles dependen da clasificación e de se o contexto se mostra antes ou despois):

SELECT time,millis,review_body FROM amazon
WHERE (time = 'ВРЕМЯ_СОБЫТИЯ' AND millis < МИЛЛИСЕКУНДЫ_СОБЫТИЯ) OR (time < 'ВРЕМЯ_СОБЫТИЯ')
ORDER BY time DESC, millis DESC
LIMIT КОЛИЧЕСТВО_СТРОК_КОНТЕКСТА
SETTINGS max_threads=1

Dado que a solicitude envíase case inmediatamente despois de que ClickHouse devolve a liña correspondente, acaba na caché e, en xeral, a solicitude execútase con bastante rapidez e consome un pouco de CPU (normalmente a solicitude leva uns ~6 ms na miña máquina virtual).

Mostra novas mensaxes en tempo real

Para mostrar as mensaxes entrantes en tempo (case) real, simplemente executamos a solicitude unha vez cada poucos segundos, lembrando a última marca de tempo que atopamos antes.

Exemplos de comandos

Como se ven os comandos logscli típicos na práctica?

Se descargaches o conxunto de datos de Amazon que mencionei ao comezo do artigo, podes executar os seguintes comandos:

# Показать строки, где встречается слово walmart
$ logscli -F 'walmart' | less

# Показать самые свежие 10 строк, где встречается "terrible"
$ logscli -F terrible -limit 10

# То же самое без -limit:
$ logscli -F terrible | head -n 10

# Показать все строки, подходящие под /times [0-9]/, написанные для vine и у которых высокий рейтинг
$ logscli -E 'times [0-9]' -where="vine='Y' AND star_rating>4" | less

# Показать все строки со словом "panic" и 3 строки контекста вокруг
$ logscli -F 'panic' -C 3 | less

# Непрерывно показывать новые строки со словом "5-star"
$ logscli -F '5-star' -tailf

referencias

O código de utilidade (sen documentación) está dispoñible en github en https://github.com/YuriyNasretdinov/logscli. Gustaríame escoitar os teus pensamentos sobre a miña idea dunha interface de consola para ver rexistros baseados en ClickHouse.

Fonte: www.habr.com

Engadir un comentario