Analisis log Nginx nggunakake Amazon Athena lan Cube.js

Biasane, produk komersial utawa alternatif open-source, kayata Prometheus + Grafana, digunakake kanggo ngawasi lan nganalisa operasi Nginx. Iki minangka pilihan sing apik kanggo ngawasi utawa analytics wektu nyata, nanging ora trep banget kanggo analisis sejarah. Ing sumber apa wae sing populer, volume data saka log nginx berkembang kanthi cepet, lan kanggo nganalisa data sing akeh, logis nggunakake sing luwih khusus.

Ing artikel iki aku bakal pitutur marang kowe carane sampeyan bisa nggunakake Athena kanggo njelasno log, njupuk Nginx minangka conto, lan aku bakal nuduhake carane ngumpul dashboard analitis saka data iki nggunakake framework cube.js mbukak-sumber. Mangkene arsitektur solusi lengkap:

Analisis log Nginx nggunakake Amazon Athena lan Cube.js

TL:DR;
Link menyang dashboard rampung.

Kanggo ngumpulake informasi sing digunakake lancar d, kanggo pangolahan - AWS Kinesis Data Firehose ΠΈ AWS Lem, kanggo panyimpenan - AWS S3. Nggunakake bundel iki, sampeyan bisa nyimpen ora mung log nginx, nanging uga acara liyane, uga log layanan liyane. Sampeyan bisa ngganti sawetara bagean sing padha kanggo tumpukan sampeyan, contone, sampeyan bisa nulis log menyang kinesis langsung saka nginx, ngliwati fluentd, utawa nggunakake logstash kanggo iki.

Nglumpukake log Nginx

Secara default, log Nginx katon kaya iki:

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" "-"

Bisa diurai, nanging luwih gampang kanggo mbenerake konfigurasi Nginx supaya bisa ngasilake log ing 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 kanggo panyimpenan

Kanggo nyimpen log, kita bakal nggunakake S3. Iki ngidini sampeyan nyimpen lan nganalisa log ing sak panggonan, amarga Athena bisa langsung nggarap data ing S3. Mengko ing artikel aku bakal pitutur marang kowe carane nambah lan proses log bener, nanging pisanan kita kudu ember resik ing S3, kang ora ana liyane bakal disimpen. Sampeyan kudu nimbang luwih dhisik ing wilayah ngendi sampeyan bakal nggawe ember, amarga Athena ora kasedhiya ing kabeh wilayah.

Nggawe sirkuit ing console Athena

Ayo nggawe tabel ing Athena kanggo log. Perlu kanggo nulis lan maca yen sampeyan nggunakake Kinesis Firehose. Bukak konsol Athena lan gawe tabel:

Nggawe tabel 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');

Nggawe Kinesis Firehose Stream

Kinesis Firehose bakal nulis data sing ditampa saka Nginx menyang S3 ing format sing dipilih, dibagi dadi direktori ing format YYYY/MM/DD/HH. Iki bakal migunani nalika maca data. Sampeyan bisa, mesthi, nulis langsung menyang S3 saka fluentd, nanging ing kasus iki sampeyan kudu nulis JSON, lan iki ora efisien amarga ukuran gedhe saka file. Kajaba iku, nalika nggunakake PrestoDB utawa Athena, JSON minangka format data sing paling alon. Dadi mbukak console Kinesis Firehose, klik "Gawe stream pangiriman", pilih "langsung PUT" ing kolom "pangiriman":

Analisis log Nginx nggunakake Amazon Athena lan Cube.js

Ing tab sabanjure, pilih "Konversi format rekaman" - "Aktif" lan pilih "Apache ORC" minangka format rekaman. Miturut sawetara riset Owen O'Malley, iki minangka format optimal kanggo PrestoDB lan Athena. Kita nggunakake tabel sing digawe ing ndhuwur minangka skema. Elinga yen sampeyan bisa nemtokake lokasi S3 ing kinesis; mung skema sing digunakake saka tabel. Nanging yen sampeyan nemtokake lokasi S3 sing beda, sampeyan ora bakal bisa maca cathetan kasebut saka tabel iki.

Analisis log Nginx nggunakake Amazon Athena lan Cube.js

Kita milih S3 kanggo panyimpenan lan ember sing digawe sadurunge. Aws Glue Crawler, sing bakal dakkandhakake mengko, ora bisa digunakake karo prefiks ing ember S3, mula penting kanggo ninggalake kosong.

Analisis log Nginx nggunakake Amazon Athena lan Cube.js

Opsi sing isih bisa diganti gumantung saka beban sampeyan; Aku biasane nggunakake sing standar. Elinga yen kompresi S3 ora kasedhiya, nanging ORC nggunakake komprèsi asli minangka standar.

lancar d

Saiki kita wis ngatur nyimpen lan nampa log, kita kudu ngatur ngirim. Kita bakal nggunakake lancar d, amarga aku Ruby, nanging sampeyan bisa nggunakake Logstash utawa ngirim log menyang kinesis langsung. Server Fluentd bisa diluncurake kanthi pirang-pirang cara, aku bakal ngandhani babagan docker amarga gampang lan trep.

Pisanan, kita butuh file konfigurasi fluent.conf. Gawe lan tambahake sumber:

jinis maju
port 24224
ikatan 0.0.0.0

Saiki sampeyan bisa miwiti server Fluentd. Yen sampeyan butuh konfigurasi sing luwih maju, pindhah menyang Hub Docker Ana pandhuan rinci, kalebu cara ngumpulake gambar sampeyan.

$ 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

Konfigurasi iki nggunakake path /fluentd/log kanggo cache log sadurunge ngirim. Sampeyan bisa nindakake tanpa iki, nanging banjur nalika sampeyan miwiti maneh, sampeyan bisa ilang kabeh sing di-cache karo pegawe bali-bejat. Sampeyan uga bisa nggunakake port apa wae; 24224 minangka port Fluentd standar.

Saiki kita wis mlaku Fluentd, kita bisa ngirim log Nginx ing kana. Kita biasane mbukak Nginx ing wadhah Docker, saengga Docker duwe driver logging asli kanggo 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

Yen sampeyan mbukak Nginx kanthi beda, sampeyan bisa nggunakake file log, Fluentd duwe file buntut plugin.

Ayo nambahake parsing log sing dikonfigurasi ing ndhuwur menyang konfigurasi Fluent:

<filter YOUR-NGINX-TAG.*>
  @type parser
  key_name log
  emit_invalid_record_to_error false
  <parse>
    @type json
  </parse>
</filter>

Lan ngirim log menyang Kinesis nggunakake kinesis firehose plugin:

<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

Yen sampeyan wis ngatur kabeh kanthi bener, banjur sawise sawetara wektu (kanthi standar, Kinesis ngrekam nampa data sapisan saben 10 menit) sampeyan kudu ndeleng file log ing S3. Ing menu "monitoring" Kinesis Firehose sampeyan bisa ndeleng jumlah data sing direkam ing S3, uga kesalahan. Aja lali menehi akses nulis menyang ember S3 menyang peran Kinesis. Yen Kinesis ora bisa ngurai soko, bakal nambah kesalahan menyang ember sing padha.

Saiki sampeyan bisa ndeleng data ing Athena. Ayo goleki panjalukan paling anyar sing kesalahane bali:

SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;

Pindai kabeh cathetan kanggo saben panyuwunan

Saiki log kita wis diproses lan disimpen ing S3 ing ORC, dikompres lan siap dianalisis. Kinesis Firehose malah ngatur dadi direktori saben jam. Nanging, anggere tabel ora dipisahake, Athena bakal mbukak data kabeh wektu ing saben panyuwunan, kanthi pangecualian sing langka. Iki minangka masalah gedhe amarga rong alasan:

  • Volume data saya tambah akeh, alon-alon pitakon;
  • Athena ditagih adhedhasar volume data sing dipindai, kanthi minimal 10 MB saben panyuwunan.

Kanggo ndandani iki, kita nggunakake AWS Glue Crawler, sing bakal nyusup data ing S3 lan nulis informasi partisi menyang Metastore Glue. Iki bakal ngidini kita nggunakake partisi minangka panyaring nalika takon Athena, lan mung bakal mindai direktori sing ditemtokake ing pitakonan kasebut.

Nggawe Amazon Glue Crawler

Amazon Glue Crawler mindhai kabeh data ing ember S3 lan nggawe tabel kanthi partisi. Nggawe Glue Crawler saka AWS Glue console lan nambah ember ngendi sampeyan nyimpen data. Sampeyan bisa nggunakake siji crawler kanggo sawetara ember, ing kasus iki bakal nggawe tabel ing basis data sing ditemtokake kanthi jeneng sing cocog karo jeneng ember. Yen sampeyan arep nggunakake data iki kanthi rutin, priksa manawa sampeyan ngatur jadwal peluncuran Crawler supaya cocog karo kabutuhan sampeyan. Kita nggunakake siji Crawler kanggo kabeh tabel, sing mlaku saben jam.

Tabel partisi

Sawise diluncurake pisanan crawler, tabel kanggo saben ember sing dipindai kudu katon ing basis data sing ditemtokake ing setelan kasebut. Bukak konsol Athena lan temokake tabel kanthi log Nginx. Ayo coba maca soko:

SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
  partition_0 = '2019' AND
  partition_1 = '04' AND
  partition_2 = '08' AND
  partition_3 = '06'
  );

Pitakonan iki bakal milih kabeh rekaman sing ditampa antarane jam 6 esuk nganti jam 7 esuk tanggal 8 April 2019. Nanging kepiye luwih efisien tinimbang mung maca saka tabel sing ora dipisahake? Ayo goleki lan pilih cathetan sing padha, nyaring kanthi cap wektu:

Analisis log Nginx nggunakake Amazon Athena lan Cube.js

3.59 detik lan 244.34 megabyte data ing set data kanthi mung seminggu log. Coba saringan kanthi partisi:

Analisis log Nginx nggunakake Amazon Athena lan Cube.js

Luwih cepet, nanging sing paling penting - mung 1.23 megabyte data! Iku bakal luwih murah yen ora kanggo minimal 10 megabyte saben request ing reregan. Nanging isih luwih apik, lan ing dataset gedhe prabΓ©dan bakal luwih nyengsemaken.

Nggawe dashboard nggunakake Cube.js

Kanggo ngumpulake dashboard, kita nggunakake kerangka analitis Cube.js. Wis cukup akeh fungsi, nanging kita kasengsem ing loro: kemampuan kanggo otomatis nggunakake saringan partisi lan data pre-agregasi. Iku nggunakake skema data skema data, ditulis ing Javascript kanggo generate SQL lan nglakokakΓ© query database. Kita mung kudu nunjukake carane nggunakake panyaring partisi ing skema data.

Ayo nggawe aplikasi Cube.js anyar. Amarga kita wis nggunakake tumpukan AWS, iku logis kanggo nggunakake Lambda kanggo panyebaran. Sampeyan bisa nggunakake cithakan ekspres kanggo generasi yen sampeyan arep dadi tuan rumah backend Cube.js ing Heroku utawa Docker. Dokumentasi nggambarake wong liya cara hosting.

$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena

Variabel lingkungan digunakake kanggo ngatur akses database ing cube.js. Generator bakal nggawe file .env sing bisa nemtokake kunci sampeyan Athena.

Saiki kita butuh skema data, ing ngendi kita bakal nuduhake persis carane log kita disimpen. Ing kana sampeyan uga bisa nemtokake cara ngetung metrik kanggo dashboard.

Ing direktori schema, nggawe file Logs.js. Mangkene conto model data kanggo nginx:

Kode model

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`
    }
  }
});

Ing kene kita nggunakake variabel FILTER_PARAMSkanggo ngasilake query SQL kanthi filter partisi.

Kita uga nyetel metrik lan paramèter sing arep ditampilake ing dashboard lan nemtokake pra-agregasi. Cube.js bakal nggawe tabel tambahan kanthi data sing wis dikumpulake lan bakal nganyari data kanthi otomatis nalika teka. Iki ora mung nyepetake pitakon, nanging uga nyuda biaya nggunakake Athena.

Ayo ditambahake informasi iki menyang file skema data:

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`
      )
    }
  }
}

Kita nemtokake ing model iki yen perlu kanggo pre-agregat data kanggo kabeh metrik sing digunakake, lan nggunakake partisi miturut sasi. Pemisahan pra-agregasi bisa nyepetake ngumpulake lan nganyari data kanthi signifikan.

Saiki kita bisa ngumpulake dashboard!

Cube.js backend nyedhiyakake REST API lan sakumpulan perpustakaan klien kanggo kerangka kerja ngarep sing populer. Kita bakal nggunakake versi React saka klien kanggo mbangun dashboard. Cube.js mung nyedhiyakake data, mula kita butuh perpustakaan visualisasi - aku seneng recharts, nanging sampeyan bisa nggunakake sembarang.

Server Cube.js nampa panjalukan ing format JSON, sing nemtokake metrik sing dibutuhake. Contone, kanggo ngetung jumlah kesalahan sing diwenehake Nginx saben dina, sampeyan kudu ngirim panjaluk ing ngisor iki:

{
  "measures": ["Logs.errorCount"],
  "timeDimensions": [
    {
      "dimension": "Logs.createdAt",
      "dateRange": ["2019-01-01", "2019-01-07"],
      "granularity": "day"
    }
  ]
}

Ayo nginstal klien Cube.js lan perpustakaan komponen React liwat NPM:

$ npm i --save @cubejs-client/core @cubejs-client/react

Kita ngimpor komponen cubejs ΠΈ QueryRendererkanggo ngundhuh data, lan ngumpulake dashboard:

Kode dashboard

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>
        );
      }}
    />
  )
}

sumber Dashboard kasedhiya ing KodeSandbox.

Source: www.habr.com

Add a comment