Cara Membangun Plugin Apache APISIX dari 0 hingga 1?

Qi Guo

Qi Guo

February 16, 2022

Ecosystem

Selama beberapa bulan terakhir, pengguna komunitas telah menambahkan banyak plugin ke Apache APISIX, memperkaya ekosistem Apache APISIX. Dari sudut pandang pengguna, munculnya plugin yang lebih beragam tentu merupakan hal yang baik, karena mereka memenuhi lebih banyak harapan pengguna untuk gateway yang "satu atap" dan "multi-fungsi" di atas penyempurnaan kinerja tinggi dan latensi rendah dari Apache APISIX.

Tidak ada artikel di blog Apache APISIX yang tampaknya membahas secara detail tentang proses pengembangan plugin. Jadi, mari kita lihat proses tersebut dari perspektif pengembang plugin dan lihat bagaimana sebuah plugin tercipta!

Artikel ini mendokumentasikan proses pengembangan plugin file-logger oleh seorang insinyur front-end tanpa pengalaman back-end. Sebelum menyelami detail proses implementasi, kami akan memperkenalkan secara singkat fungsionalitas file-logger.

Pengenalan Plugin file-logger

file-logger mendukung pembuatan format log kustom menggunakan metadata plugin Apache APISIX. Pengguna dapat menambahkan data permintaan dan respons dalam format JSON ke file log melalui plugin file-logger, atau mendorong aliran data log ke lokasi yang ditentukan.

Bayangkan ini: saat memantau log akses suatu rute, kita tidak hanya peduli dengan nilai data permintaan dan respons tertentu, tetapi juga ingin menulis data log ke file tertentu. Di sinilah plugin file-logger dapat digunakan untuk membantu mencapai tujuan tersebut.

how it works

Kita dapat menggunakan file-logger untuk menulis data log ke file log tertentu guna menyederhanakan proses pemantauan dan debugging.

Bagaimana cara mengimplementasikan plugin?

Setelah memperkenalkan fitur file-logger, Anda akan memiliki pemahaman yang lebih baik tentang plugin ini. Berikut adalah penjelasan rinci tentang bagaimana saya, seorang pengembang front-end tanpa pengalaman server-side, mengembangkan plugin untuk Apache APISIX dan menambahkan tes yang sesuai untuknya.

Menentukan nama dan prioritas plugin

Buka Panduan Pengembangan Plugin Apache APISIX dan sesuai urutan prioritas, Anda perlu menentukan dua hal berikut:

  1. Tentukan kategori plugin.
  2. Prioritaskan plugin dan perbarui file conf/config-default.yaml.

Karena pengembangan file-logger ini adalah plugin tipe logging, saya merujuk pada nama dan urutan plugin logging yang ada untuk Apache APISIX dan menempatkan file-logger di sini.

file-logger's position

Setelah berkonsultasi dengan penulis plugin lain dan anggota komunitas yang antusias, akhirnya nama plugin file-logger dan prioritas 399 dikonfirmasi.

Perhatikan bahwa prioritas plugin terkait dengan urutan eksekusi; semakin tinggi nilai prioritas, semakin maju eksekusinya. Dan urutan nama plugin tidak terkait dengan urutan eksekusi.

Membuat file plugin yang dapat dieksekusi minimal

Setelah mengonfirmasi nama dan prioritas plugin, Anda dapat membuat file kode plugin kami di direktori apisix/plugins/. Ada dua hal yang perlu diperhatikan di sini:

  • Jika file kode plugin dibuat langsung di direktori apisix/plugins/, tidak perlu mengubah file Makefile.
  • Jika plugin Anda memiliki direktori kode sendiri, Anda perlu memperbarui file Makefile, silakan merujuk ke Panduan Pengembangan Plugin Apache APISIX untuk langkah-langkah detailnya.
  1. Di sini kami membuat file file-logger.lua di direktori apisix/plugins/.
  2. Kemudian kami akan menyelesaikan versi yang diinisialisasi berdasarkan example-plugin.
-- Memperkenalkan modul yang kita butuhkan di header local log_util = require("apisix.utils.log-util") local core = require("apisix.core") local plugin = require("apisix.plugin") local ngx = ngx -- Mendeklarasikan nama plugin local plugin_name = "file-logger" -- Mendefinisikan format skema plugin local schema = { type = "object", properties = { path = { type = "string" }, }, required = {"path"} } -- Skema metadata plugin local metadata_schema = { type = "object", properties = { log_format = log_util.metadata_schema_log_format } } local _M = { version = 0.1, priority = 399, name = plugin_name, schema = schema, metadata_schema = metadata_schema } -- Memeriksa apakah konfigurasi plugin benar function _M.check_schema(conf, schema_type) if schema_type == core.schema.TYPE_METADATA then return core.schema.check(metadata_schema, conf) end return core.schema.check(schema, conf) end -- Fase log function _M.log(conf, ctx) core.log.warn("conf: ", core.json.encode(conf)) core.log.warn("ctx: ", core.json.encode(ctx, true)) end return _M

Setelah file plugin yang dapat digunakan minimal siap, data konfigurasi plugin dan data terkait permintaan dapat dioutput ke file error.log melalui core.log.warn(core.json.encode(conf)) dan core.log.warn("ctx: ", core.json.encode(ctx, true)).

Mengaktifkan dan menguji plugin

Berikut adalah beberapa langkah untuk pengujian. Untuk menguji apakah plugin dapat berhasil mencetak data plugin dan informasi data terkait permintaan yang kami konfigurasikan ke file log error, kita perlu mengaktifkan plugin dan membuat rute pengujian.

  1. Siapkan upstream pengujian secara lokal (upstream pengujian yang digunakan dalam artikel ini adalah 127.0.0.1:3030/api/hello, yang saya buat secara lokal).

  2. Buat rute melalui perintah curl dan aktifkan plugin baru kami.

    curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "plugins": { "file-logger": { "path": "logs/file.log" } }, "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:3030": 1 } }, "uri": "/api/hello" }'

    Anda kemudian akan melihat kode status 200, yang menunjukkan bahwa rute berhasil dibuat.

  3. Jalankan perintah curl untuk mengirim permintaan ke rute untuk menguji apakah plugin file-logger telah diaktifkan.

    curl -i http://127.0.0.1:9080/api/hello HTTP/1.1 200 OK ... hello, world
  4. Di file logs/error.log akan ada catatan:

    record in logs/error.log

    Seperti yang Anda lihat, path: logs/file.log yang kami konfigurasikan untuk plugin dalam parameter conf telah berhasil disimpan. Pada titik ini, kami telah berhasil membuat plugin yang dapat digunakan minimal yang mencetak parameter conf dan ctx dalam fase logging.

    Setelah itu, kami dapat menulis fungsi inti untuk plugin file-logger.lua langsung di file kodenya. Di sini kami dapat langsung menjalankan perintah apisix reload untuk memuat ulang kode plugin terbaru tanpa perlu me-restart Apache APISIX.

Fungsi utama plugin file-logger adalah menulis data log. Setelah bertanya kepada orang lain dari komunitas dan memeriksa informasi, saya mempelajari tentang pustaka IO Lua, dan mengonfirmasi bahwa logika fungsi plugin kira-kira adalah langkah-langkah berikut.

  1. Setelah setiap permintaan yang diterima, output data log ke path yang dikonfigurasikan oleh plugin.

    1. Pertama, dapatkan nilai path dalam file-logger melalui conf dalam fase logging.
    2. Kemudian, pustaka IO Lua digunakan untuk membuat, membuka, menulis, menyegarkan cache, dan menutup file.
  2. Menangani kesalahan seperti gagal membuka file, gagal membuat file, dll.

    local function write_file_data(conf, log_message) local msg, err = core.json.encode(log_message) if err then return core.log.error("message json serialization failed, error info : ", err) end local file, err = io_open(conf.path, 'a+') if not file then core.log.error("failed to open file: ", conf.path, ", error info: ", err) else local ok, err = file:write(msg, '\n') if not ok then core.log.error("failed to write file: ", conf.path, ", error info: ", err) else file:flush() end file:close() end end
  3. Merujuk ke kode sumber plugin http-logger, saya menyelesaikan metode untuk meneruskan data log ke data log yang ditulis dan beberapa penilaian dan pemrosesan metadata.

    function _M.log(conf, ctx) local metadata = plugin.plugin_metadata(plugin_name) local entry if metadata and metadata.value.log_format and core.table.nkeys(metadata.value.log_format) > 0 then entry = log_util.get_custom_format_log(ctx, metadata.value.log_format) else entry = log_util.get_full_log(ngx, conf) end write_file_data(conf, entry) end

Memvalidasi dan menambahkan tes

Memvalidasi catatan log

Karena plugin file-logger diaktifkan saat rute pengujian dibuat dan path dikonfigurasikan sebagai logs/file.log, kita dapat dengan mudah mengirim permintaan ke rute pengujian untuk memverifikasi hasil pengumpulan log pada titik ini.

curl -i http://127.0.0.1:9080/api/hello

Di logs/file.log yang sesuai, kita dapat melihat bahwa setiap catatan disimpan dalam format JSON. Setelah memformat salah satu data, tampilannya seperti ini.

{ "server": { "hostname": "....", "version": "2.11.0" }, "client_ip": "127.0.0.1", "upstream": "127.0.0.1:3030", "route_id": "1", "start_time": 1641285122961, "latency": 13.999938964844, "response": { "status": 200, "size": 252, "headers": { "server": "APISIX/2.11.0", "content-type": "application/json; charset=utf-8", "date": "Tue, 04 Jan 2022 08:32:02 GMT", "vary": "Accept-Encoding", "content-length": "19", "connection": "close", "etag": "\"13-5j0ZZR0tI549fSRsYxl8c9vAU78\"" } }, "service_id": "", "request": { "querystring": {}, "size": 87, "method": "GET", "headers": { "host": "127.0.0.1:9080", "accept": "*/*", "user-agent": "curl/7.77.0" }, "url": "http://127.0.0.1:9080/api/hello", "uri": "/api/hello" } }

Ini menyimpulkan validasi pengumpulan catatan log. Hasil validasi menunjukkan bahwa plugin berhasil diluncurkan dan mengembalikan data yang sesuai.

Menambahkan lebih banyak tes untuk plugin

Untuk bagian kode add_block_preprocessor, saya bingung saat pertama kali menulisnya karena saya tidak memiliki pengalaman sebelumnya dengan Perl. Setelah meneliti, saya menyadari cara yang benar untuk menggunakannya: jika kita tidak menulis asersi request dan no_error_log di bagian data, maka asersi default adalah sebagai berikut.

--- request GET /t --- no_error_log [error]

Setelah mempertimbangkan beberapa file pengujian logging lainnya, saya membuat file file-logger.t di direktori t/plugin/.

Setiap file pengujian dibagi oleh **DATA** menjadi bagian pendahuluan dan bagian data. Karena tidak ada klasifikasi yang jelas tentang dokumen terkait pengujian di situs web resmi, Anda dapat merujuk ke materi terkait di akhir artikel untuk detail lebih lanjut. Berikut adalah salah satu kasus pengujian yang telah saya selesaikan setelah merujuk ke materi terkait.

use t::APISIX 'no_plan'; no_long_string(); no_root_location(); add_block_preprocessor(sub { my ($block) = @_; if (! $block->request) { $block->set_value("request", "GET /t"); } if (! $block->no_error_log && ! $block->error_log) { $block->set_value("no_error_log", "[error]"); } }); run_tests; __DATA__ === TEST 1: sanity --- config location /t { content_by_lua_block { local configs = { -- full configuration { path = "file.log" }, -- property "path" is required { path = nil } } local plugin = require("apisix.plugins.file-logger") for i = 1, #configs do ok, err = plugin.check_schema(configs[i]) if err then ngx.say(err) else ngx.say("done") end end } } --- response_body_like done property "path" is required

Ini menyimpulkan sesi penambahan tes plugin.

Ringkasan

Di atas adalah seluruh proses implementasi plugin Apache APISIX dari 0 sebagai pemula di backend. Saya memang menemukan banyak kendala dalam proses pengembangan plugin, tetapi untungnya ada banyak teman yang antusias di komunitas Apache APISIX yang membantu saya memecahkan masalah, sehingga pengembangan dan pengujian plugin file-logger berjalan relatif lancar. Jika Anda tertarik dengan plugin ini, atau ingin melihat detail plugin, Anda dapat merujuk ke dokumentasi resmi Apache APISIX.

Apache APISIX juga saat ini sedang mengerjakan plugin lain untuk mendukung lebih banyak layanan integrasi, jadi jika Anda tertarik, jangan ragu untuk memulai diskusi di GitHub Discussion, atau melalui mailing list.

Referensi

Tags: