Typesch gi kommerziell Produkter oder fäerdeg Open-Source Alternativen, wéi Prometheus + Grafana, benotzt fir d'Operatioun vun Nginx ze iwwerwaachen an ze analyséieren. Dëst ass eng gutt Optioun fir Iwwerwaachung oder Echtzäitanalyse, awer net ganz praktesch fir historesch Analyse. Op all populär Ressource wiisst de Volume vun Daten aus nginx Logbicher séier, a fir eng grouss Quantitéit un Daten ze analyséieren, ass et logesch eppes méi spezialiséiert ze benotzen.
An dësem Artikel wäert ech Iech soen wéi Dir kënnt benotzen
TL:DR;
Fir Informatiounen ze sammelen déi mir benotzen
Sammelen Nginx Logbicher
Par défaut kucken Nginx Logbicher sou eppes aus:
4/9/2019 12:58:17 PM1.1.1.1 - - [09/Apr/2019:09:58:17 +0000] "GET /sign-up HTTP/2.0" 200 9168 "https://example.com/sign-in" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" "-"
4/9/2019 12:58:17 PM1.1.1.1 - - [09/Apr/2019:09:58:17 +0000] "GET /sign-in HTTP/2.0" 200 9168 "https://example.com/sign-up" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" "-"
Si kënne parséiert ginn, awer et ass vill méi einfach d'Nginx Konfiguratioun ze korrigéieren sou datt et Logbicher am JSON produzéiert:
log_format json_combined escape=json '{ "created_at": "$msec", '
'"remote_addr": "$remote_addr", '
'"remote_user": "$remote_user", '
'"request": "$request", '
'"status": $status, '
'"bytes_sent": $bytes_sent, '
'"request_length": $request_length, '
'"request_time": $request_time, '
'"http_referrer": "$http_referer", '
'"http_x_forwarded_for": "$http_x_forwarded_for", '
'"http_user_agent": "$http_user_agent" }';
access_log /var/log/nginx/access.log json_combined;
S3 fir Stockage
Fir Logbicher ze späicheren, benotze mir S3. Dëst erlaabt Iech Logbicher op enger Plaz ze späicheren an z'analyséieren, well Athena direkt mat Daten am S3 kann schaffen. Méi spéit am Artikel wäert ech Iech soen wéi Dir d'Protokoller korrekt addéiere a veraarbecht, awer als éischt brauche mir e propperen Eemer am S3, an deem näischt anescht gespäichert gëtt. Et ass derwäert am Viraus ze berücksichtegen a wéi enger Regioun Dir Ären Eemer wäert kreéieren, well Athena ass net an alle Regiounen verfügbar.
Schafe vun engem Circuit an der Athena Konsol
Loosst eis en Dësch an Athena fir Logbicher erstellen. Et ass néideg fir béid ze schreiwen an ze liesen wann Dir plangt Kinesis Firehose ze benotzen. Öffnen d'Athena Konsole a kreéiert en Dësch:
SQL Dësch Kreatioun
CREATE EXTERNAL TABLE `kinesis_logs_nginx`(
`created_at` double,
`remote_addr` string,
`remote_user` string,
`request` string,
`status` int,
`bytes_sent` int,
`request_length` int,
`request_time` double,
`http_referrer` string,
`http_x_forwarded_for` string,
`http_user_agent` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.ql.io.orc.OrcSerde'
STORED AS INPUTFORMAT
'org.apache.hadoop.hive.ql.io.orc.OrcInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat'
LOCATION
's3://<YOUR-S3-BUCKET>'
TBLPROPERTIES ('has_encrypted_data'='false');
Erstellt Kinesis Firehose Stream
Kinesis Firehose schreift d'Daten, déi vun Nginx op S3 an dem gewielte Format kritt ginn, a verdeelt se an Verzeichnisser am Format JJJJ/MM/DD/HH. Dëst wäert praktesch kommen wann Dir Daten liest. Dir kënnt natierlech direkt op S3 vu fluentd schreiwen, awer an dësem Fall musst Dir JSON schreiwen, an dëst ass net effizient wéinst der grousser Gréisst vun de Dateien. Zousätzlech, wann Dir PrestoDB oder Athena benotzt, ass JSON dat luesst Dateformat. Also öffnen d'Kinesis Firehose Konsole, klickt op "Liwwerstroum erstellen", wielt "direkt PUT" am Feld "Liwwerung":
An der nächster Tab, wielt "Record Format Konversioun" - "Enabled" a wielt "Apache ORC" als Opnamformat. Laut e puer Fuerschungen
Mir wielen S3 fir Späicheren an den Eemer dee mir virdru erstallt hunn. Aws Glue Crawler, iwwer deen ech e bësse méi spéit schwätzen, kann net mat Präfixe an engem S3 Eemer schaffen, also ass et wichteg et eidel ze loossen.
Déi reschtlech Optiounen kënnen ofhängeg vun Ärer Belaaschtung geännert ginn; Ech benotzen normalerweis déi Standard. Notéiert datt S3 Kompressioun net verfügbar ass, awer ORC benotzt native Kompressioun als Standard.
fléissend
Elo datt mir d'Späicheren an d'Empfang vun Logbicher konfiguréiert hunn, musse mir d'Sendung konfiguréieren. Mir wäerten benotzen
Als éischt brauche mir d'Konfiguratiounsdatei fluent.conf. Erstellt et a füügt Quell dobäi:
Hafen 24224
binden 0.0.0.0
Elo kënnt Dir de Fluentd Server starten. Wann Dir eng méi fortgeschratt Konfiguratioun braucht, gitt op
$ docker run
-d
-p 24224:24224
-p 24224:24224/udp
-v /data:/fluentd/log
-v <PATH-TO-FLUENT-CONF>:/fluentd/etc fluentd
-c /fluentd/etc/fluent.conf
fluent/fluentd:stable
Dës Konfiguratioun benotzt de Wee /fluentd/log
Logbicher ze cache ier Dir schéckt. Dir kënnt ouni dëst maachen, awer dann, wann Dir nei start, kënnt Dir alles verléieren, dat mat der Réckbriechungsaarbecht gelagert ass. Dir kënnt och all Hafen benotzen; 24224 ass de Standard Fluentd Hafen.
Elo datt mir Fluentd lafen, kënne mir Nginx Logbicher dohinner schécken. Mir lafen normalerweis Nginx an engem Docker Container, an deem Fall huet Docker en gebiertege Logging Chauffer fir Fluentd:
$ docker run
--log-driver=fluentd
--log-opt fluentd-address=<FLUENTD-SERVER-ADDRESS>
--log-opt tag="{{.Name}}"
-v /some/content:/usr/share/nginx/html:ro
-d
nginx
Wann Dir Nginx anescht leeft, kënnt Dir Logdateien benotzen, Fluentd huet
Loosst eis de Log Parsing uewe konfiguréiert an d'Fluent Konfiguratioun addéieren:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
A schéckt Logbicher op Kinesis benotzt
<match YOUR-NGINX-TAG.*>
@type kinesis_firehose
region region
delivery_stream_name <YOUR-KINESIS-STREAM-NAME>
aws_key_id <YOUR-AWS-KEY-ID>
aws_sec_key <YOUR_AWS-SEC_KEY>
</match>
Athena
Wann Dir alles richteg konfiguréiert hutt, dann no enger Zäit (par défaut, Kinesis records kritt Daten eemol all 10 Minutten) sollt Dir Logdateien an S3 gesinn. Am Menü "Iwwerwaachung" vu Kinesis Firehose kënnt Dir gesinn wéi vill Daten am S3 opgeholl ginn, souwéi Feeler. Vergiesst net Schreiwen Zougang zum S3 Eemer fir d'Kinesis Roll ze ginn. Wann Kinesis eppes net parse konnt, füügt et d'Feeler an deeselwechten Eemer.
Elo kënnt Dir d'Donnéeën an Athena kucken. Loosst eis déi lescht Ufroe fannen, fir déi mir Feeler zréckginn:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Scannen all records fir all Ufro
Elo sinn eis Logbicher veraarbecht a gespäichert an S3 am ORC, kompriméiert a prett fir Analyse. Kinesis Firehose huet se souguer an Verzeechnes fir all Stonn organiséiert. Wéi och ëmmer, soulaang den Dësch net opgedeelt ass, lued Athena all Zäit Daten op all Ufro, mat rare Ausnahmen. Dëst ass e grousse Problem aus zwee Grënn:
- De Volume vun den Donnéeën wiisst konstant, verlangsamt Ufroen;
- Athena gëtt berechent baséiert op dem Volume vun den gescannten Donnéeën, mat engem Minimum vun 10 MB pro Ufro.
Fir dëst ze fixéieren, benotze mir AWS Glue Crawler, deen d'Donnéeën am S3 krabbelt an d'Partitionsinformatioun an de Glue Metastore schreift. Dëst erlaabt eis Partitionen als Filter ze benotzen beim Ufro vun Athena, an et scannt nëmmen d'Verzeichnungen, déi an der Ufro spezifizéiert sinn.
Amazon Glue Crawler opsetzen
Amazon Glue Crawler scannt all d'Donnéeën am S3 Eemer a kreéiert Dëscher mat Partitionen. Erstellt e Glue Crawler vun der AWS Glue Konsole a füügt en Eemer un, wou Dir d'Donnéeën späichert. Dir kënnt e Crawler fir e puer Eemer benotzen, an deem Fall gëtt et Tabellen an der spezifizéierter Datebank mat Nimm, déi mat den Nimm vun den Eemer passen. Wann Dir plangt dës Donnéeën regelméisseg ze benotzen, gitt sécher de Crawler Startplang ze konfiguréieren fir Äre Besoinen ze passen. Mir benotzen ee Crawler fir all Dëscher, déi all Stonn leeft.
Opgedeelt Dëscher
Nom éischte Start vum Crawler sollten Dëscher fir all gescannt Eemer an der Datebank erscheinen, déi an den Astellunge spezifizéiert ass. Öffnen d'Athena Konsole a fannt den Dësch mat Nginx Logbicher. Loosst eis probéieren eppes ze liesen:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Dës Ufro wäert all records auswielen, déi tëscht 6 a 7 den 8. Abrëll 2019 kritt goufen. Awer wéi vill méi effizient ass dëst wéi just aus engem net-opgedeelt Dësch ze liesen? Loosst eis erausfannen a wielt déiselwecht Opzeechnungen, filtert se no Zäitstempel:
3.59 Sekonnen an 244.34 Megabytes vun Daten op engem Dataset mat nëmmen enger Woch Logbicher. Loosst eis e Filter duerch Partition probéieren:
E bësse méi séier, awer am wichtegsten - nëmmen 1.23 Megabytes vun Daten! Et wier vill méi bëlleg wann net fir de Minimum 10 Megabytes pro Ufro am Präiss. Awer et ass nach ëmmer vill besser, an op groussen Datesätz wäert den Ënnerscheed vill méi beandrockend sinn.
Bauen en Dashboard mat Cube.js
Fir den Dashboard ze sammelen, benotze mir den analytesche Kader Cube.js. Et huet zimmlech vill Funktiounen, awer mir sinn an zwee interesséiert: d'Fäegkeet fir automatesch Partitionsfilteren an d'Pre-Aggregatioun vun Daten ze benotzen. Et benotzt Dateschema
Loosst eis eng nei Cube.js Applikatioun erstellen. Well mir schonn den AWS Stack benotzen, ass et logesch Lambda fir den Deployment ze benotzen. Dir kënnt d'Express Template fir d'Generatioun benotzen wann Dir plangt de Cube.js Backend an Heroku oder Docker ze hosten. D'Dokumentatioun beschreift anerer
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
Ëmweltvariablen gi benotzt fir den Zougang zu der Datebank an cube.js ze konfiguréieren. De Generator wäert eng .env Datei erstellen, an där Dir Är Schlësselen fir
Elo brauche mir
Am Verzeechnes schema
, eng Datei erstellen Logs.js
. Hei ass e Beispill Datemodell fir nginx:
Modell Code
const partitionFilter = (from, to) => `
date(from_iso8601_timestamp(${from})) <= date_parse(partition_0 || partition_1 || partition_2, '%Y%m%d') AND
date(from_iso8601_timestamp(${to})) >= date_parse(partition_0 || partition_1 || partition_2, '%Y%m%d')
`
cube(`Logs`, {
sql: `
select * from part_demo_kinesis_bucket
WHERE ${FILTER_PARAMS.Logs.createdAt.filter(partitionFilter)}
`,
measures: {
count: {
type: `count`,
},
errorCount: {
type: `count`,
filters: [
{ sql: `${CUBE.isError} = 'Yes'` }
]
},
errorRate: {
type: `number`,
sql: `100.0 * ${errorCount} / ${count}`,
format: `percent`
}
},
dimensions: {
status: {
sql: `status`,
type: `number`
},
isError: {
type: `string`,
case: {
when: [{
sql: `${CUBE}.status >= 400`, label: `Yes`
}],
else: { label: `No` }
}
},
createdAt: {
sql: `from_unixtime(created_at)`,
type: `time`
}
}
});
Hei benotze mir d'Variabel
Mir setzen och d'Metriken an d'Parameteren, déi mir um Dashboard wëllen weisen an d'Pre-Aggregatioune spezifizéieren. Cube.js wäert zousätzlech Dëscher mat pre-aggregéierten Donnéeën erstellen an d'Donnéeën automatesch aktualiséieren wéi se ukommen. Dëst beschleunegt net nëmmen Ufroen, awer reduzéiert och d'Käschte fir Athena ze benotzen.
Loosst eis dës Informatioun an d'Dateschemadatei addéieren:
preAggregations: {
main: {
type: `rollup`,
measureReferences: [count, errorCount],
dimensionReferences: [isError, status],
timeDimensionReference: createdAt,
granularity: `day`,
partitionGranularity: `month`,
refreshKey: {
sql: FILTER_PARAMS.Logs.createdAt.filter((from, to) =>
`select
CASE WHEN from_iso8601_timestamp(${to}) + interval '3' day > now()
THEN date_trunc('hour', now()) END`
)
}
}
}
Mir spezifizéieren an dësem Modell datt et néideg ass d'Donnéeën ze pre-aggregeren fir all benotzt Metriken, an d'Partitionéierung vum Mount ze benotzen.
Elo kënne mir den Dashboard zesummestellen!
Cube.js Backend bitt
De Cube.js Server akzeptéiert d'Ufro an
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
Loosst eis de Cube.js Client an d'React Komponentbibliothéik iwwer NPM installéieren:
$ npm i --save @cubejs-client/core @cubejs-client/react
Mir importéieren Komponenten cubejs
и QueryRenderer
fir d'Donnéeën erofzelueden an d'Dashboard ze sammelen:
Dashboard Code
import React from 'react';
import { LineChart, Line, XAxis, YAxis } from 'recharts';
import cubejs from '@cubejs-client/core';
import { QueryRenderer } from '@cubejs-client/react';
const cubejsApi = cubejs(
'YOUR-CUBEJS-API-TOKEN',
{ apiUrl: 'http://localhost:4000/cubejs-api/v1' },
);
export default () => {
return (
<QueryRenderer
query={{
measures: ['Logs.errorCount'],
timeDimensions: [{
dimension: 'Logs.createdAt',
dateRange: ['2019-01-01', '2019-01-07'],
granularity: 'day'
}]
}}
cubejsApi={cubejsApi}
render={({ resultSet }) => {
if (!resultSet) {
return 'Loading...';
}
return (
<LineChart data={resultSet.rawData()}>
<XAxis dataKey="Logs.createdAt"/>
<YAxis/>
<Line type="monotone" dataKey="Logs.errorCount" stroke="#8884d8"/>
</LineChart>
);
}}
/>
)
}
Dashboard Quelle sinn op
Source: will.com