ααΆααααααΆ ααα·αααααΆαα·ααααααα α¬αααααΎααααααααΎαα αα αααααααααα½α ααΆααααα ααΌα ααΆ Prometheus + Grafana ααααΌαααΆαααααΎααΎααααΈααΆαααΆα αα·ααα·ααΆαααααα·ααααα·ααΆααααα Nginx α αααααΊααΆαααααΎαααααα’αααααΆααααΆααααα½ααα·αα·ααα α¬ααΆααα·ααΆαααΆααααααααΆααΆααααααα ααα»αααααα·αααΆααααα½ααααααΆααααΆααα·ααΆααααααααα·ααΆααααααααααα αα ααΎααααΆαααααααα·ααααΆαα½α ααα·ααΆααααα·ααααααααΈαααααα ααα» nginx αααα»αααααΎαα‘αΎααααΆαααΆαααα αα α αΎαααΎααααΈαα·ααΆααα·αααααααα½αα ααα½ααα ααΆααα ααα»αααααα»αααΆαααααΎα’αααΈααααα·αααααΆααααα
αα
αααα»αα’αααααααααααα»αααΉαααααΆααα’αααααΈαααααααα’αααα’αΆα
ααααΎ
ααΎααααΈαααααΌαααααααΆαααΎαααααΎ
ααΆααααααΌααααααα ααα» Nginx
ααΆαααααΆαααΎα αααααα ααα» Nginx ααΎααα ααΌα αααα
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" "-"
αα½αααΆα’αΆα αααααΆα ααα»ααααααΆααΆααααααΆααααα½ααααα»αααΆααααααααΌαααΆαααααααα ααΆαααααααα Nginx ααΌα ααααααΆαααααΎααααααα ααα»αα αααα»α JSONα
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 αααααΆαααααα»α
ααΎααααΈαααααΆαα»ααααααα ααα» ααΎαααΉαααααΎ S3 α αααα’αα»ααααΆαα±ααα’ααααααααΆαα»α αα·ααα·ααΆααααααα ααα»αα αααααααααα½α αααααΆα Athena α’αΆα ααααΎααΆαααΆαα½ααα·αααααααα αααα»α S3 αααααααΆααα α’ααααααααααΆαααααα»αααΉαααααΆααα’αααααΈαααααααααα αα·αααααΎαααΆααααααα ααα»α±ααααΆαααααΉαααααΌα ααα»ααααααααΌαααΎαααααΌαααΆααα»αααα’αΆααα αααα»α S3 αααααααΆαα’αααΈααααααααααΉαααααΌαααΆααααααΆαα»αααα ααΆααΆαααααααα·α αΆαααΆααΆαα»αααΆααΎαααααααΆαααα’αααααΉααααααΎααα»αααααα’ααα ααΈααααα Athena αα·αααΆααα ααααααααααααΆααα’ααα
ααΆααααααΎαααααααΈαα αααα»ααα»αααΌα Athena
ααααααααΎαααΆααΆααα Athena αααααΆαααααααα ααα»α ααΆααααΌαααΆααααααΆααααΆααααΆαααααα αα·αααΆαα’αΆα ααααα·αααΎα’αααααΆαααααααααααΎ Kinesis Firehose α ααΎααα»αααΌα Athena α αΎααααααΎαααΆααΆαα
ααΆααααααΎαααΆααΆα SQL
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');
ααΆααααααΎαααααααΈα Kinesis Firehose
Kinesis Firehose ααΉαααααααα·αααααααααααα½αααΆαααΈ Nginx αα S3 αααα»ααααααααααααΆαααααΎαααΎα ααααααα ααααΆαα ααΆαααααα»ααααααα YYYY/MM/DD/HHα ααΆααΉαααΆααααααααααα αααα’αΆααα·ααααααα ααΆααΆααα·αααΆααα’αααα’αΆα ααααααααααααΆαααα S3 ααΈααααΆααααααΆα ααα»αααααααα»αααααΈαααα’αααααΉαααααΌαααααα JSON α αΎαααΆαα·αααΆαααααα·αααααΆααααααΆαααααα αααααα―αααΆαα ααΎαααΈαααααα αα αααααααΎ PrestoDB α¬ Athena JSON ααΊααΆαααααααα·ααααααααΊααααα»αα ααΌα ααααααΎααα»αααΌα Kinesis Firehose α α»α "αααααΎαααΆαα ααα αΆα" ααααΎαααΎα "αααααααΆαα PUT" αα αααα»αααΆα "ααΆαααΉααααααΌα"α
αα
αααα»αααααΆαααααααΆαα ααααΎαααΎα "ααΆααααααααααααααααΆααα" - "ααΆαααΎαααααΎαααΆα" α αΎαααααΎαααΎα "Apache ORC" ααΆααααααααα αααβααΎβααΆαβααΆαβααααΆαααααΆαβαα½αβα
ααα½α
ααΎαααααΎαααΎα S3 αααααΆααααΆααααα»α αα·ααα»ααααααΎαααΆααααααΎααα»αα Aws Glue Crawler ααααααα»αααΉααα·ααΆαα’αααΈααααα·α ααααααα αα·αα’αΆα ααααΎαααΆαααΆαα½ααα»ααααααα αααα»ααα»α S3 ααΆααα ααΌα ααααααΆααΆααΆαααααΆαααααα»αααΆααα»αααΆα±αααα αααα
αααααΎαααααα αααα’αΆα ααααΌαααΆαααααΆααααααΌαα’αΆαααααααΎααααα»αααααα’ααα ααΆααααααΆαααα»αααααΎαααααΎαααααΆαααΎαα α αααΆαααΆααΆααααα αΆαα S3 αα·αααΆααα ααα»αααα ORC ααααΎααΆααααα αΆααααΎαααΆαααααΆαααΎαα
ααααΆαα
α₯α‘αΌαβαααβααΎαβααΆαβαααααβαα
ααΆααααααααβααΆαβαααααΆβαα»α αα·αβααα½αβααΆαβα αΎα ααΎαβααααΌαβαααααβαα
ααΆααααααααβααΆαβααααΎα ααΎαααΉαααααΎ
ααααΌαααΎαααααΌαααΆαα―αααΆαααααααα ααΆαααααααα fluent.conf α αααααΎαααΆ α αΎααααααααααααα
ααααααα 24224
α
α α©
α₯α‘αΌααααα’αααα’αΆα
α
αΆααααααΎααααΆαααΈααα Fluentd α ααααα·αααΎα’αααααααΌαααΆαααΆαααααααα
ααΆααααααααααααα·ααααααααααααααα ααΌαα
αΌααα
ααΆαα
$ 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
ααΆαααααααααααααΎααααΌα /fluentd/log
ααΎααααΈαααααΆαα»ααααααα ααα»αα»ααααααααΎα α’αααβα’αΆα
βααααΎβαααβααααΆαβααΆ ααα»ααααβαααααΆααβααβαα
βαααβαααβα’αααβα
αΆααααααΎαβα‘αΎαβαα·α α’αααβα’αΆα
βααΆαααααβα’αααΈβαααααβαααΆαβαααβααΆαβαα»αβαααα»αβααααΆααβαααααΆααβααΆαα½αβααΉαβαααααΆααβααααααα α’αααααα’αΆα
ααααΎα
αααααΆαα½αααααΆαααα 24224 ααΊααΆα
ααα Fluentd ααααΆαααΎαα
α₯α‘αΌαααα ααΎαααΆα Fluentd αααα»αααααΎαααΆα ααΎαα’αΆα ααααΎαααααα ααα» Nginx αα ααΈαααα ααΆααααααΆααΎαααααΎαααΆα Nginx αα αααα»α Docker container αααα»αααααΈααα Docker ααΆααααααα·ααΈαααααΆαααααα ααα»ααΎααααααΆαα 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
ααααα·αααΎα’αααααααΎαααΆα Nginx αα»αααααΆα’αααα’αΆα
ααααΎα―αααΆααααααα ααα» Fluentd ααΆα
αααααααααααΆαααααααααα ααα»αααααΆαααααααα ααΆααααααααααΆαααΎαα ααΆαααααααα ααΆααααααααααααΆααααααΆαα
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
αα·αααΆαααααΎαααααα ααα»αα
Kinesis αααααααΎ
<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
ααααα·αααΎα’αααααΆαααααααα ααΆααααααααααααααααΆαααΆαααααΉαααααΌα αααααΆαααααα½αααααα»α (ααΆαααααΆαααΎα αααααααααΆ Kinesis ααΆαααα½ααα·αααααααααααααααΆαα 10 ααΆααΈαααα) α’ααααα½αααααΎαα―αααΆααααααα ααα»αα αααα»α S3 α αα αααα»ααααΊαα»α "ααΆααααα½ααα·αα·ααα" αα Kinesis Firehose α’αααα’αΆα ααΎαααΎαα ααα½ααα·αααααααααααααΌαααΆααααααααΆαα αααα»α S3 ααααΌα ααΆααα α»ααααααα αα»αααααα ααααααα·αααα·ααααααα ααΆαααα»α S3 αα ααΆαααα½ααΆααΈ Kinesisα ααααα·αααΎ Kinesis αα·αα’αΆα αααα’αααΈαα½αααΆααα ααΆααΉαααααααααα α»ααα αααα»ααα»ααααα½αα
α₯α‘αΌααααα’αααα’αΆα ααΎααα·αααααααα αααα»α Athena α α αΌαααΎααααααααααααΎα α»αααααααααα»ααααααΎαααΆααααα‘ααααα α»αα
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
αααα»ααααααααΆααααΆαααααΎαα»αααΈαα½αα
α₯α‘αΌαααα αααααα ααα»ααααααΎαααααΌαααΆαααααΎαααΆα αα·ααααααΆαα»ααα αααα»α S3 αα αααα»α ORC αααααΆααααα αΆαα αα·ααα½α ααΆαααααααΆααααΆααα·ααΆαα Kinesis Firehose αααααΆαααααα ααα½αααΆαα αααα»ααααααΈααααααααααΆααααααα ααααααΆαααΆααααα αααΆαααΆααΆααΆααα·αααααΌαααΆααααα αα Athena ααΉααααα»ααα·αααααααααααααααα ααΎααΆααααααΎ αααααΆαααααΈααΎααααααααααα αααααΊααΆαααα αΆαααααααΆααα ααα»ααααΈαα
- ααα·ααΆααα·αααααααααα»αααΎαα‘αΎαα₯αααααα αααααααααΏααααα½αα
- Athena ααααΌαβααΆαβα ααβαα·ααααααααβαααβααα’ααβααΎβααα·ααΆαβααβαα·ααααααβαααβααΆαβααααα αααβααΆαβα’αααααααΆ 10 MB αααα»αβαα½αβααααΎα
ααΎααααΈαα½ααα»αααΆ ααΎαααααΎ AWS Glue Crawler αααααΉααα»ααααα·αααααααα αααα»α S3 α αΎααααααααααααΆαααΆαααΆααα ααΆαα Glue Metastore α ααΆααΉαα’αα»ααααΆαα±ααααΎαααααΎααΆαααΆαααΆααααααα ααααα½α Athena α αΎαααΆααΉαααααααααααααααΆααααααΆαααα αααα»ααααα½αααα»αααααα
ααΆαααα‘αΎα Amazon Glue Crawler
Amazon Glue Crawler ααααααα·ααααααααΆααα’αααα αααα»ααα»α S3 αα·ααααααΎαααΆααΆααααααΆαααΆαααΆαα αααααΎα Glue Crawler ααΈαα»αααΌα AWS Glue α αΎααααααααα»ααααα’ααααααααΆαα»ααα·ααααααα α’αααβα’αΆα βααααΎ crawler αα½αβαααααΆααβααΆααβαα»αβααΆβα αααΎα αααβαααα»αβααααΈβαααβααΆβααΉαβαααααΎαβααΆααΆαβαααα»αβααΌαααααΆαβαα·ααααααβαααβααΆαβαααααΆααβααΆαα½αβααΉαβαααααβαααβααααΌαβααααΆβααΉαβαααααβααααβαα»αα ααααα·αααΎα’αααααΆαααααααααααΎαα·αααααααααααΆαααα αΆα ααααΌαααααΆααααΆααααααα ααΆααααααααααΆααα·ααΆαααααΆαααΎαααααΎαααΆααααα Crawler α±ααααααΉααααααΌαααΆαααααα’αααα ααΎαααααΎ Crawler αα½ααααααΆααααΆααΆαααΆααα’αα αααααααΎαααΆααααααΆααααααα
ααΆααΆααααα αα
αααααΆααααΈααΆαααΎαααααΎαααΆαααααΌααααα crawler ααΆααΆααααααΆαααα»ααααααααΈαα½αααα½ααααααα αΆααα αααα»αααΌαααααΆααα·αααααααααααΆααααααΆαααα αααα»αααΆααααααα ααΎααα»αααΌα Athena α αΎααααααααααΆααΆααααααΆααααααα ααα» Nginx α αααβααΆαβα’αΆαβααααα·α βααΎαα
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
αααα½ααααααΉαααααΎαααΎααααααααααΆααΆααα’αααααααα½αααΆααα α ααααααααα 6 ααααΉα ααα 7 ααααΉα αα ααααααΈ 8 ααααααΆ ααααΆα 2019α ααα»αααα ααΎβααΆβααΆαβααααα·αααααΆαβααΆαβααΆαβα’αΆαβααΈβααΆααΆαβαααβαα·αβααΆαβααΆαβα αααΎαβαα βαααβ? ααααααααααα αα·αααααΎαααΎααααααααααΆααΌα ααααΆ ααααααααα½αααΆααΆααααααααΆα
3.59 αα·ααΆααΈ αα·α 244.34 ααααΆαααααα·αααααααα ααΎαααα»ααα·αααααααααααΆααααααα ααα»ααααΉααααα½ααααααΆα αααα»αααααα αααααΆααααααααααααΆαααΆαα
ααΏαααΆαααααα·α ααα»ααααααααΆαααααα»α - αα·ααααααααααΉααα 1.23 ααααΆαα! ααΆααΉαααΆαααααααααααΆαααα ααααα·αααΎαα·αααααααααΆααα’αααααααΆ 10 ααα αααΆαααααα»ααα½αααααΎαααα»αααΆαααααααααααα ααα»ααααααΆαα αααααααΎαααΆααα»α α αΎααα ααΎαααα»ααα·αααααααα ααΆααα»αααααΆααΉαααΆαααααα½αα’ααα αΆααα’αΆααααααα
αααααΎαααααΆααααααααααααααααααΎ Cube.js
ααΎααααΈαααααΌααααα»αααααΆααααααααααα ααΎαααααΎααααααααααα·ααΆα Cube.js α ααΆβααΆαβαα»αααΆαβα
αααΎαβααΆαα ααα»ααααβααΎαβα
αΆααβα’αΆααααααβααΎβααΈαα αααααααΆαβαααα»αβααΆαβααααΎβααΆαβααΆαβαααβαααααβαααααααα· αα·αβααΆαβαααααΌαβαα·ααααααβααΆαα»αα ααΆααααΎαααααααΆααααα·αααααα
ααααααααΎααααααα·ααΈ Cube.js ααααΈα αααααΆαααΎααααα»αααααΎααα AWS αα½α
α αΎα ααΆααΆα‘αΌααΈαααααα»αααΆαααααΎ Lambda αααααΆααααΆαααΆαααααααΆαα α’αααα’αΆα
ααααΎααααΌαα αααααααΆααααααΆαα ααααα·αααΎα’αααααΆααααααααααα
ααααααα·ααΈ Cube.js backend αα
αααα»α Heroku α¬ Dockerα α―αααΆααα·αααααΆα’αααΈα’αααααα
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
α’αααααα·ααααΆαααααΌαααΆαααααΎααΎααααΈααααααα
ααΆααααααααααΆαα
αΌαααααΎααΌαααααΆααα·αααααααα
αααα»α cube.js α αααΆαααΈαααααΎαααΉααααααΎαα―αααΆα .env αααα’αααα’αΆα
αααααΆααααααααα’ααααααααΆαα
α₯α‘αΌααααααΎαααααΌαααΆα
αα
αααα»ααα schema
αααααΎαα―αααΆα Logs.js
. αααααΊααΆααααΌαα·ααααααα§ααΆα ααααααααΆαα nginxα
αααααΌαααααΌ
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`
}
}
});
αα
ααΈαααααΎααααα»αααααΎα’ααα
ααΎαααααΆαααααααααααα αα·ααααΆαααΆαααααααααααΎαα αααααα αΆααα ααΎααααΆααααααααααα αα·ααααααΆααααΆααααααΌααααα»αααΆαα»αα Cube.js ααΉααααααΎαααΆααΆαααααααααΆαα½αααΉααα·αααααααααααΆααααααΌααααα»αααΆαα»α α αΎαααΉαααααΎαα αα α»ααααααααΆααα·αααααααααααααααααααααα·αα αααααΆαααααα ααααα·αααααΉααααααααΎαααααΏααααα½αααα»ααααααα ααα»αααααααααΆααααΆαααααααααΆαα αααΆαααΎααΆαααααΎααααΆαα Athena αααααα
αααααααααααααααΆαααααα αααα»αα―αααΆααααααααΆααααα·ααααααα
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`
)
}
}
}
ααΎααααααΆαααα
αααα»αααααΌαααααΆ ααΆα
αΆαααΆα
ααααα»αααΆααααααΌααα·ααααααααΆαα»ααααααΆααααααααααΆααα’αααααααΆαααααΎ α αΎαααααΎααΆααααα
ααααΆαααα
α₯α‘αΌααααααΎαα’αΆα αααααΌααααα»αααααΆαααααααααααααΆα!
αααααααΆαααααα Cube.js ααααα
αααΆαααΈααα Cube.js ααα½αααααααΎαα
αααα»α
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
αααααα‘αΎααααααα·ααΈ Cube.js αα·ααααααΆααααααΆαααΆαα» React ααΆαααα NPMα
$ npm i --save @cubejs-client/core @cubejs-client/react
ααΎαααΆαα
αΌααααΆαααΆαα» cubejs
ΠΈ QueryRenderer
ααΎααααΈααΆααααα·αααααα αα·ααααααΌαααααΆαααααααααααα
αααααΌαααααΆααααααααααα
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 ααΆααα
ααααα: www.habr.com