Aplikasi praktis dari ELK. Konfigurasikan logstash

Pendahuluan


Menyebarkan sistem berikutnya, dihadapkan dengan kebutuhan untuk memproses sejumlah besar berbagai log. Sebagai alat yang dipilih ELK. Artikel ini akan membahas pengalaman kami dengan menyetel tumpukan ini.

Kami tidak menetapkan tujuan untuk menggambarkan semua kemungkinannya, tetapi kami ingin berkonsentrasi tepat pada penyelesaian masalah praktis. Ini disebabkan oleh fakta bahwa di hadapan sejumlah besar dokumentasi dan gambar siap pakai, ada banyak jebakan, setidaknya kami menemukannya.

Kami menyebarkan tumpukan melalui docker-compose. Selain itu, kami memiliki docker-compose.yml yang ditulis dengan baik, yang memungkinkan kami untuk meningkatkan tumpukan tanpa masalah. Dan bagi kami tampaknya kemenangan sudah dekat, sekarang kita akan sedikit memutar agar sesuai dengan kebutuhan kita dan hanya itu.

Sayangnya, upaya untuk menyempurnakan sistem untuk menerima dan memproses log dari aplikasi kami tidak berhasil. Karena itu, kami memutuskan bahwa ada baiknya mengeksplorasi setiap komponen secara terpisah, dan kemudian kembali ke hubungan mereka.

Jadi, kami mulai dengan logstash.

Lingkungan, penyebaran, luncurkan Logstash di wadah


Untuk penyebaran, kami menggunakan docker-compose, percobaan yang dijelaskan di sini dilakukan pada MacOS dan Ubuntu 18.0.4.

Gambar logstash yang terdaftar dengan kami di docker-compose.yml asli adalah docker.elastic.co/logstash/logstash:6.3.2

Kami akan menggunakannya untuk eksperimen.

Untuk menjalankan logstash, kami menulis docker-compose.yml terpisah. Tentu saja, dimungkinkan untuk meluncurkan gambar dari baris perintah, tetapi kami memang memecahkan masalah tertentu, di mana semuanya dari docker-compose diluncurkan.

Secara singkat tentang file konfigurasi


Sebagai berikut dari deskripsi, logstash dapat dijalankan baik untuk satu saluran, dalam hal ini, perlu mentransfer file * .conf atau untuk beberapa saluran, dalam hal ini perlu ditransfer file pipelines.yml, yang, pada gilirannya, akan terhubung ke file .conf untuk setiap saluran.
Kami pergi ke jalan kedua. Bagi kami, itu lebih universal dan dapat diukur. Oleh karena itu, kami membuat pipelines.yml, dan membuat direktori jalur pipa tempat kami akan meletakkan file .conf untuk setiap saluran.

Di dalam wadah ada file konfigurasi lain - logstash.yml. Kami tidak menyentuhnya, gunakan apa adanya.

Jadi, struktur direktori kami:



Untuk mendapatkan input, untuk saat ini, kami percaya bahwa ini adalah tcp pada port 5046, dan untuk output kami akan menggunakan stdout.

Berikut ini adalah konfigurasi sederhana untuk proses pertama. Karena tugas awal adalah meluncurkan.

Jadi, kami memiliki docker-compose.yml ini

version: '3' networks: elk: volumes: elasticsearch: driver: local services: logstash: container_name: logstash_one_channel image: docker.elastic.co/logstash/logstash:6.3.2 networks: - elk ports: - 5046:5046 volumes: - ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro - ./config/pipelines:/usr/share/logstash/config/pipelines:ro 

Apa yang kita lihat di sini?

  1. Jaringan dan volume diambil dari buruh pelabuhan asli-compose.yml (yang mana seluruh tumpukan diluncurkan) dan saya pikir mereka tidak secara signifikan mempengaruhi keseluruhan gambar di sini.
  2. Kami membuat satu layanan logstash dari gambar docker.elastic.co/logstash/logstash:6.3.2 dan memberinya nama logstash_one_channel.
  3. Kami meneruskan port 5046 di dalam wadah ke port internal yang sama.
  4. Kami memetakan file pengaturan saluran kami ./config/pipelines.yml ke file /usr/share/logstash/config/pipelines.yml di dalam wadah, tempat logstash akan mengambilnya dan membuatnya hanya-baca, untuk berjaga-jaga.
  5. Kami menampilkan direktori ./config/pipelines, di mana kami memiliki file dengan pengaturan saluran, di direktori / usr / share / logstash / config / pipeline dan juga membuatnya hanya-baca.



File Pipelines.yml

 - pipeline.id: HABR pipeline.workers: 1 pipeline.batch.size: 1 path.config: "./config/pipelines/habr_pipeline.conf" 

Di sini, satu saluran dengan pengidentifikasi HABR dan jalur ke file konfigurasinya dijelaskan.

Dan akhirnya file "./config/pipelines/habr_pipeline.conf"

 input { tcp { port => "5046" } } filter { mutate { add_field => [ "habra_field", "Hello Habr" ] } } output { stdout { } } 

Mari kita tidak menjelaskan deskripsinya untuk saat ini, cobalah menjalankan:

 docker-compose up 

Apa yang kita lihat

Wadah mulai. Kami dapat memeriksa operasinya:

 echo '13123123123123123123123213123213' | nc localhost 5046 

Dan kita melihat jawabannya di konsol wadah:



Tetapi pada saat yang sama, kita juga melihat:

logstash_one_channel | [2019-04-29T11: 28: 59.790] [ERROR] [logstash.licensechecker.licensereader] Tidak dapat mengambil informasi lisensi dari server lisensi {: message => "Elasticsearch Tidak Dapat Dicapai: [http: // elasticsearch: 9200 /] [Manticore :: ResolutionFailure] elasticsearch ", ...

logstash_one_channel | [2019-04-29T11: 28: 59.894] [INFO] [logstash.pipeline] Pipeline mulai berhasil {: pipeline_id => ". Monitoring-logstash" ,: thread => "# <Thread: 0x119abb86 run>"}

logstash_one_channel | [2019-04-29T11: 28: 59.988] [INFO] [logstash.agent] Pipa berjalan {: count => 2 ,: running_pipelines => [: HABR ,: ". Monitoring-logstash"] ,: non_running_pipelines => [ ]}
logstash_one_channel | [2019-04-29T11: 29: 00.015] [ERROR] [logstash.inputs.metrics] X-Pack diinstal pada Logstash tetapi tidak pada Elasticsearch. Silakan instal X-Pack di Elasticsearch untuk menggunakan fitur pemantauan. Fitur lain mungkin tersedia.
logstash_one_channel | [2019-04-29T11: 29: 00,526] [INFO] [logstash.agent] Berhasil memulai titik akhir API Logstash {: port => 9600}
logstash_one_channel | [2019-04-29T11: 29: 04.478] [INFO] [logstash.outputs.elasticsearch] Menjalankan pemeriksaan kesehatan untuk melihat apakah koneksi Elasticsearch berfungsi {: healthcheck_url => http: // elasticsearch: 9200 / ,: path => "/"}
l ogstash_one_channel | [2019-04-29T11: 29: 04.487] [ PERINGATAN] [logstash.outputs.elasticsearch] Mencoba untuk menghidupkan kembali koneksi ke instance ES yang mati, tetapi mengalami kesalahan. {: url => “ elasticsearch : 9200 /” ,: error_type => LogStash :: Outputs :: ElasticSearch :: HttpClient :: Pool :: HostUnreachableError ,: error => “Elasticsearch Tidak Dapat Dicapai: [http: // elasticsearch: 9200 / ] [Manticore :: ResolutionFailure] elasticsearch ”}
logstash_one_channel | [2019-04-29T11: 29: 04.704] [INFO] [logstash.licensechecker.licensereader] Menjalankan pemeriksaan kesehatan untuk melihat apakah koneksi Elasticsearch berfungsi {: healthcheck_url => http: // elasticsearch: 9200 / ,: path => "/"}
logstash_one_channel | [2019-04-29T11: 29: 04.710] [ PERINGATAN] [logstash.licensechecker.licensereader] Berusaha membangkitkan kembali koneksi ke instance ES yang mati, tetapi mengalami kesalahan. {: url => “ elasticsearch : 9200 /” ,: error_type => LogStash :: Outputs :: ElasticSearch :: HttpClient :: Pool :: HostUnreachableError ,: error => “Elasticsearch Tidak Dapat Dicapai: [http: // elasticsearch: 9200 / ] [Manticore :: ResolutionFailure] elasticsearch ”}

Dan log kami terus merayap.

Di sini saya menyoroti pesan hijau bahwa pipa mulai berhasil, merah - pesan kesalahan dan kuning - pesan tentang upaya untuk menghubungi elasticsearch : 9200.
Ini terjadi karena logstash.conf yang termasuk dalam gambar memiliki pemeriksaan ketersediaan elasticsearch. Bagaimanapun, logstash mengasumsikan bahwa ia berfungsi sebagai bagian dari tumpukan Elk, dan kami memisahkannya.

Anda dapat bekerja, tetapi tidak nyaman.

Solusinya adalah dengan menonaktifkan pemeriksaan ini melalui variabel lingkungan XPACK_MONITORING_ENABLED.

Buat perubahan ke docker-compose.yml dan jalankan kembali:

 version: '3' networks: elk: volumes: elasticsearch: driver: local services: logstash: container_name: logstash_one_channel image: docker.elastic.co/logstash/logstash:6.3.2 networks: - elk environment: XPACK_MONITORING_ENABLED: "false" ports: - 5046:5046 volumes: - ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro - ./config/pipelines:/usr/share/logstash/config/pipelines:ro 

Sekarang semuanya baik-baik saja. Wadah siap untuk eksperimen.

Kita dapat mengetik lagi di konsol berikutnya:

 echo '13123123123123123123123213123213' | nc localhost 5046 

Dan lihat:

 logstash_one_channel | { logstash_one_channel | "message" => "13123123123123123123123213123213", logstash_one_channel | "@timestamp" => 2019-04-29T11:43:44.582Z, logstash_one_channel | "@version" => "1", logstash_one_channel | "habra_field" => "Hello Habr", logstash_one_channel | "host" => "gateway", logstash_one_channel | "port" => 49418 logstash_one_channel | } 

Bekerja dalam satu saluran


Jadi, kami mulai. Sekarang Anda benar-benar dapat meluangkan waktu untuk mengkonfigurasi logstash secara langsung. Kami tidak akan menyentuh file pipelines.yml untuk saat ini, kami akan melihat apa yang dapat Anda peroleh dengan bekerja dengan satu saluran.

Saya harus mengatakan bahwa prinsip umum bekerja dengan file konfigurasi saluran dijelaskan dengan baik dalam panduan resmi, di sini
Jika Anda ingin membaca dalam bahasa Rusia, maka kami menggunakan artikel ini di sini (tetapi sintaks kueri sudah tua di sana, kami harus mempertimbangkan ini).

Mari kita berurutan dari bagian Input. Kami sudah melihat pekerjaan di tcp. Apa lagi yang menarik di sini?

Tes pesan menggunakan detak jantung


Ada peluang yang sangat menarik untuk menghasilkan pesan pengujian otomatis.
Untuk melakukan ini, Anda harus memasukkan plugin heartbean di bagian input.

 input { heartbeat { message => "HeartBeat!" } } 

Hidupkan, mulai satu menit sekali untuk menerima

 logstash_one_channel | { logstash_one_channel | "@timestamp" => 2019-04-29T13:52:04.567Z, logstash_one_channel | "habra_field" => "Hello Habr", logstash_one_channel | "message" => "HeartBeat!", logstash_one_channel | "@version" => "1", logstash_one_channel | "host" => "a0667e5c57ec" logstash_one_channel | } 

Kami ingin lebih sering, kami perlu menambahkan parameter interval.
Ini adalah bagaimana kami akan menerima pesan setiap 10 detik.

 input { heartbeat { message => "HeartBeat!" interval => 10 } } 

Mengambil data dari file


Kami juga memutuskan untuk melihat mode file. Jika ini bekerja secara normal dengan file, maka ada kemungkinan bahwa tidak ada agen yang diperlukan, setidaknya untuk penggunaan lokal.

Menurut deskripsi, mode operasi harus mirip dengan tail -f, yaitu membaca baris baru atau, sebagai opsi, membaca seluruh file.

Jadi apa yang ingin kita dapatkan:

  1. Kami ingin mendapatkan baris yang ditambahkan ke satu file log.
  2. Kami ingin menerima data yang ditulis ke beberapa file log, sambil dapat membagikan apa yang berasal.
  3. Kami ingin memeriksa bahwa ketika memulai kembali logstash tidak akan menerima data ini lagi.
  4. Kami ingin memeriksa apakah logstash dinonaktifkan, dan data terus ditulis ke file, maka ketika kami menjalankannya, kami akan mendapatkan data ini.

Untuk melakukan percobaan, tambahkan baris lain ke docker-compose.yml, buka direktori tempat kami meletakkan file.

 version: '3' networks: elk: volumes: elasticsearch: driver: local services: logstash: container_name: logstash_one_channel image: docker.elastic.co/logstash/logstash:6.3.2 networks: - elk environment: XPACK_MONITORING_ENABLED: "false" ports: - 5046:5046 volumes: - ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro - ./config/pipelines:/usr/share/logstash/config/pipelines:ro - ./logs:/usr/share/logstash/input 

Dan ubah bagian input di habr_pipeline.conf

 input { file { path => "/usr/share/logstash/input/*.log" } } 

Kita mulai:

 docker-compose up 

Untuk membuat dan merekam file log, kita akan menggunakan perintah:

  echo '1' >> logs/number1.log 

 { logstash_one_channel | "host" => "ac2d4e3ef70f", logstash_one_channel | "habra_field" => "Hello Habr", logstash_one_channel | "@timestamp" => 2019-04-29T14:28:53.876Z, logstash_one_channel | "@version" => "1", logstash_one_channel | "message" => "1", logstash_one_channel | "path" => "/usr/share/logstash/input/number1.log" logstash_one_channel | } 

Ya, itu berhasil!

Pada saat yang sama, kami melihat bahwa kami secara otomatis menambahkan bidang jalur. Jadi di masa mendatang, kita dapat memfilter catatan dengan itu.

Mari kita coba lagi:

 echo '2' >> logs/number1.log 

 { logstash_one_channel | "host" => "ac2d4e3ef70f", logstash_one_channel | "habra_field" => "Hello Habr", logstash_one_channel | "@timestamp" => 2019-04-29T14:28:59.906Z, logstash_one_channel | "@version" => "1", logstash_one_channel | "message" => "2", logstash_one_channel | "path" => "/usr/share/logstash/input/number1.log" logstash_one_channel | } 


Dan sekarang ke file lain:

  echo '1' >> logs/number2.log 

 { logstash_one_channel | "host" => "ac2d4e3ef70f", logstash_one_channel | "habra_field" => "Hello Habr", logstash_one_channel | "@timestamp" => 2019-04-29T14:29:26.061Z, logstash_one_channel | "@version" => "1", logstash_one_channel | "message" => "1", logstash_one_channel | "path" => "/usr/share/logstash/input/number2.log" logstash_one_channel | } 

Hebat! File diambil, path benar, semuanya baik-baik saja.

Hentikan logstash dan mulai ulang. Mari kita tunggu. Kesunyian. Yaitu Kami tidak menerima catatan ini lagi.

Dan sekarang percobaan paling berani.

Kami menaruh logstash dan menjalankan:

 echo '3' >> logs/number2.log echo '4' >> logs/number1.log 

Jalankan logstash lagi dan lihat:

 logstash_one_channel | { logstash_one_channel | "host" => "ac2d4e3ef70f", logstash_one_channel | "habra_field" => "Hello Habr", logstash_one_channel | "message" => "3", logstash_one_channel | "@version" => "1", logstash_one_channel | "path" => "/usr/share/logstash/input/number2.log", logstash_one_channel | "@timestamp" => 2019-04-29T14:48:50.589Z logstash_one_channel | } logstash_one_channel | { logstash_one_channel | "host" => "ac2d4e3ef70f", logstash_one_channel | "habra_field" => "Hello Habr", logstash_one_channel | "message" => "4", logstash_one_channel | "@version" => "1", logstash_one_channel | "path" => "/usr/share/logstash/input/number1.log", logstash_one_channel | "@timestamp" => 2019-04-29T14:48:50.856Z logstash_one_channel | } 

Hore! Semuanya diambil.

Tetapi, kita harus memperingatkan tentang yang berikut ini. Jika wadah dengan logstash dihapus (buruh pelabuhan berhenti logstash_one_channel && buruh pelabuhan rm logstash_one_channel), maka tidak ada yang akan diambil. Di dalam wadah, posisi file yang dibaca disimpan. Jika dijalankan dari awal, itu hanya akan menerima baris baru.

Baca file yang ada


Misalkan kita menjalankan logstash untuk pertama kalinya, tetapi kami sudah memiliki log dan kami ingin memprosesnya.
Jika kami menjalankan logstash dengan bagian input yang kami gunakan di atas, kami tidak akan mendapatkan apa pun. Hanya baris baru yang akan diproses oleh logstash.

Untuk menarik baris dari file yang ada, tambahkan baris tambahan ke bagian input:

 input { file { start_position => "beginning" path => "/usr/share/logstash/input/*.log" } } 

Selain itu, ada nuansa, ini hanya mempengaruhi file baru yang belum terlihat logstash. Untuk file yang sama yang sudah jatuh ke bidang tampilan logstash, dia sudah ingat ukurannya dan sekarang hanya akan mengambil entri baru di dalamnya.

Mari kita mempelajari bagian input. Ada banyak opsi lagi, tetapi bagi kami, untuk percobaan lebih lanjut untuk saat ini sudah cukup.

Routing dan konversi data


Mari kita coba untuk menyelesaikan masalah berikut, katakanlah kita memiliki pesan dari satu saluran, beberapa di antaranya bersifat informasi, dan sebagian lagi merupakan pesan kesalahan. Tag berbeda. Beberapa INFO, yang lain ERROR.

Kita perlu memisahkan mereka pada output. Yaitu Kami menulis pesan informasi dalam satu saluran, dan pesan kesalahan di saluran lain.

Untuk melakukan ini, pergi dari bagian input untuk memfilter dan output.

Menggunakan bagian filter, kami akan mem-parsing pesan yang masuk, mendapatkan dari hash (pasangan nilai kunci), yang sudah bisa Anda gunakan, mis. dibongkar oleh kondisi. Dan di bagian output, kami memilih pesan dan mengirim masing-masing ke saluran kami.

Parsing pesan menggunakan grok


Untuk mengurai string teks dan mendapatkan seperangkat bidang dari mereka, ada plugin khusus di bagian filter - grok.

Tidak bermaksud untuk memberikan deskripsi rinci di sini (untuk ini saya merujuk pada dokumentasi resmi ), saya akan memberikan contoh sederhana saya.

Untuk melakukan ini, Anda perlu memutuskan format jalur input. Saya memilikinya:

1 pesan INFO1
2 pesan KESALAHAN2

Yaitu Pengenal datang terlebih dahulu, lalu INFO / GALAT, lalu beberapa kata tanpa spasi.
Tidak sulit, tetapi cukup untuk memahami cara kerjanya.

Jadi, di bagian filter, di plugin grok, kita perlu mendefinisikan pola untuk mem-parsing baris kita.

Ini akan terlihat seperti ini:

 filter { grok { match => { "message" => ["%{INT:message_id} %{LOGLEVEL:message_type} %{WORD:message_text}"] } } } 

Ini pada dasarnya adalah ekspresi reguler. Pola siap pakai digunakan, seperti INT, LOGLEVEL, WORD. Deskripsi mereka, serta pola lainnya, dapat ditemukan di sini.

Sekarang, melewati filter ini, string kita akan berubah menjadi hash dari tiga bidang: message_id, message_type, message_text.

Mereka akan ditampilkan di bagian output.

Merutekan pesan di bagian output menggunakan perintah if


Di bagian keluaran, seperti yang kita ingat, kami akan membagi pesan menjadi dua aliran. Beberapa - yang iNFO, kami akan output ke konsol, dan dengan kesalahan, kami akan output ke file.

Bagaimana kami membagi posting ini? Kondisi masalah sudah meminta solusi - kami sudah memiliki bidang message_type yang dipilih, yang hanya dapat mengambil dua nilai INFO dan ERROR. Bagi dia kita akan membuat pilihan menggunakan pernyataan if.

 if [message_type] == "ERROR" { #     } else { #    stdout } 

Deskripsi bekerja dengan bidang dan operator dapat ditemukan di bagian manual resmi ini .

Sekarang, tentang kesimpulan yang sebenarnya.

Output ke konsol, semuanya jelas di sini - stdout {}

Dan di sini adalah output ke file - ingat bahwa kita menjalankan semuanya dari wadah dan agar file yang kita tulis hasilnya dapat diakses dari luar, kita perlu membuka direktori ini di docker-compose.yml.

Total:

Bagian output dari file kami terlihat seperti ini:

  output { if [message_type] == "ERROR" { file { path => "/usr/share/logstash/output/test.log" codec => line { format => "custom format: %{message}"} } } else {stdout { } } } 

Di docker-compose.yml, tambahkan volume lain ke keluaran:

 version: '3' networks: elk: volumes: elasticsearch: driver: local services: logstash: container_name: logstash_one_channel image: docker.elastic.co/logstash/logstash:6.3.2 networks: - elk environment: XPACK_MONITORING_ENABLED: "false" ports: - 5046:5046 volumes: - ./config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro - ./config/pipelines:/usr/share/logstash/config/pipelines:ro - ./logs:/usr/share/logstash/input - ./output:/usr/share/logstash/output 

Kami mulai, kami mencoba, kami melihat pembagian menjadi dua aliran.

Source: https://habr.com/ru/post/id451264/


All Articles