Dokumen ini menjelaskan cara menggunakan fitur transformasi data dari Simple Log Service untuk mentransformasi data JSON yang kompleks.
Transformasi data JSON yang kompleks dengan beberapa subkunci sebagai array
Log dari program sering kali ditulis dalam format JSON statistik. Log tersebut biasanya mencakup informasi dasar dan beberapa subkunci yang merupakan array. Sebagai contoh, sebuah server menulis log setiap menit. Log tersebut berisi status saat ini dan informasi statistik tentang server serta node klien terkait.
Contoh Log
__source__: 192.0.2.1 __topic__: content:{ "service": "search_service", "overal_status": "yellow", "servers": [ { "host": "192.0.2.1", "status": "green" }, { "host": "192.0.2.2", "status": "green" } ], "clients": [ { "host": "192.0.2.3", "status": "green" }, { "host": "192.0.2.4", "status": "red" } ] }Persyaratan Transformasi Data
Pisahkan log mentah menjadi tiga log berdasarkan bidang
topic:overall_type,client_status, danserver_status.Simpan informasi berbeda untuk nilai
topicyang berbeda.overall_type: Pertahankan jumlah server, jumlah klien, warna overall_status, dan informasi layanan.client_status: Pertahankan alamat host, status, dan informasi layanan.server_status: Pertahankan alamat host, status, dan informasi layanan.
Hasil yang Diharapkan
__source__: 192.0.2.1 __topic__: overall_type client_count: 2 overal_status: yellow server_count: 2 service: search_service __source__: 192.0.2.1 __topic__: client_status host: 192.0.2.4 status: red service: search_service __source__: 192.0.2.1 __topic__: client_status host: 192.0.2.3 status: green service: search_service __source__: 192.0.2.1 __topic__: server_status host: 192.0.2.1 status: green service: search_service __source__: 192.0.2.1 __topic__: server_status host: 192.0.2.2 status: green service: search_serviceSolusi
Pisahkan log menjadi tiga log terpisah. Untuk melakukannya, tetapkan tiga nilai berbeda pada bidang topic. Setelah pemisahan, Anda akan memiliki tiga log yang identik kecuali untuk bidang
topic.e_set("__topic__", "server_status,client_status,overall_type") e_split("__topic__")Format log setelah diproses adalah sebagai berikut:
__source__: 192.0.2.1 __topic__: server_status // Dua log lainnya memiliki `client_status` dan `overall_type` sebagai topik. Sisanya sama. content: { ...Seperti sebelumnya... }Perluas konten JSON lapisan pertama dari bidang
content, lalu hapus bidangcontent.e_json('content',depth=1) e_drop_fields("content")Format log setelah diproses adalah sebagai berikut:
__source__: 192.0.2.1 __topic__: overall_type // Dua log lainnya memiliki `client_status` dan `overall_type` sebagai topik. Sisanya sama. clients: [{"host": "192.0.2.3", "status": "green"}, {"host": "192.0.2.4", "status": "red"}] overal_status: yellow servers: [{"host": "192.0.2.1", "status": "green"}, {"host": "192.0.2.2", "status": "green"}] service: search_serviceUntuk log dengan topik
overall_type, hitung nilai untukclient_countdanserver_count.e_if(e_search("__topic__==overall_type"), e_compose( e_set("client_count", json_select(v("clients"), "length([*])", default=0)), e_set("server_count", json_select(v("servers"), "length([*])", default=0)) ))Log yang telah diproses adalah:
__topic__: overall_type server_count: 2 client_count: 2Hapus bidang yang tidak diperlukan.
e_if(e_search("__topic__==overall_type"), e_drop_fields("clients", "servers"))Pisahkan lebih lanjut log dengan topik
server_status.e_if(e_search("__topic__==server_status"), e_compose( e_split("servers"), e_json("servers", depth=1) ))Log dipisah menjadi dua log berikut:
__topic__: server_status servers: {"host": "192.0.2.1", "status": "green"} host: 192.0.2.1 status: green__topic__: server_status servers: {"host": "192.0.2.2", "status": "green"} host: 192.0.2.2 status: greenBidang relevan yang perlu dipertahankan:
e_if(e_search("__topic__==overall_type"), e_drop_fields("servers"))Anda dapat memisahkan lebih lanjut log dengan topik
client_statusdan kemudian menghapus bidang `clients`.e_if(e_search("__topic__==client_status"), e_compose( e_split("clients"), e_json("clients", depth=1), e_drop_fields("clients") ))Log dipisah menjadi dua log berikut:
__topic__: client_status host: 192.0.2.3 status: green__topic__: clients host: 192.0.2.4 status: redAturan lengkap bahasa domain-spesifik (DSL) LOG adalah sebagai berikut:
# Pisahkan log. e_set("__topic__", "server_status,client_status,overall_type") e_split("__topic__") e_json('content',depth=1) e_drop_fields("content") # Proses log overall_type. e_if(e_search("__topic__==overall_type"), e_compose( e_set("client_count", json_select(v("clients"), "length([*])", default=0)), e_set("server_count", json_select(v("servers"), "length([*])", default=0)) )) # Proses log server_status. e_if(e_search("__topic__==server_status"), e_compose( e_split("servers"), e_json("servers", depth=1) )) e_if(e_search("__topic__==overall_type"), e_drop_fields("servers")) # Proses log client_status. e_if(e_search("__topic__==client_status"), e_compose( e_split("clients"), e_json("clients", depth=1), e_drop_fields("clients") ))
Optimasi Solusi
Solusi sebelumnya mengalami masalah ketika content.servers dan content.servers kosong. Sebagai contoh, perhatikan log mentah berikut:
__source__: 192.0.2.1
__topic__:
content:{
"service": "search_service",
"overal_status": "yellow",
"servers": [ ],
"clients": [ ]
}Jika Anda menggunakan solusi sebelumnya untuk memisahkan log mentah ini menjadi tiga log, log dengan topik client_status dan server_status akan kosong.
__source__: 192.0.2.1
__topic__: overall_type
client_count: 0
overal_status: yellow
server_count: 0
service: search_service
__source__: 192.0.2.1
__topic__: client_status
service: search_service
__source__: 192.0.2.1
__topic__: server_status
host: 192.0.2.1
status: green
service: search_serviceSolusi 1
Setelah pemisahan awal, periksa apakah log dengan topik
server_statusdanclient_statuskosong. Jika ya, buang mereka.# Untuk server_status: buang jika kosong, pertahankan jika tidak. e_keep(op_and(e_search("__topic__==server_status"), json_select(v("servers"), "length([*])"))) # Untuk client_status: buang jika kosong, pertahankan jika tidak. e_keep(op_and(e_search("__topic__==client_status"), json_select(v("clients"), "length([*])")))Aturan DSL LOG lengkap adalah sebagai berikut:
# Pisahkan log. e_set("__topic__", "server_status,client_status,overall_type") e_split("__topic__") e_json('content',depth=1) e_drop_fields("content") # Proses log overall_type. e_if(e_search("__topic__==overall_type"), e_compose( e_set("client_count", json_select(v("clients"), "length([*])", default=0)), e_set("server_count", json_select(v("servers"), "length([*])", default=0)) )) # Baru: Pra-proses server_status: buang jika kosong, pertahankan jika tidak. e_keep(op_and(e_search("__topic__==server_status"), json_select(v("servers"), "length([*])"))) # Proses log server_status. e_if(e_search("__topic__==server_status"), e_compose( e_split("servers"), e_json("servers", depth=1) )) e_if(e_search("__topic__==overall_type"), e_drop_fields("servers")) # Baru: Pra-proses client_status: buang jika kosong, pertahankan jika tidak. e_keep(op_and(e_search("__topic__==client_status"), json_select(v("clients"), "length([*])"))) # Proses log client_status. e_if(e_search("__topic__==client_status"), e_compose( e_split("clients"), e_json("clients", depth=1), e_drop_fields("clients") ))Solusi 2
Periksa apakah suatu bidang kosong sebelum memisahkan log. Jika bidang tidak kosong, pisahkan log berdasarkan bidang tersebut.
# Tetapkan topik awal. e_set("__topic__", "server_status") # Jika bidang content.servers tidak kosong, pisahkan log untuk membuat log dengan topik server_status. e_if(json_select(v("content"), "length(servers[*])"), e_compose( e_set("__topic__", "server_status,overall_type"), e_split("__topic__") )) # Jika bidang content.clients tidak kosong, pisahkan lebih lanjut log untuk membuat log dengan topik client_status. e_if(op_and(e_search("__topic__==overall_type"), json_select(v("content"), "length(clients[*])")), e_compose( e_set("__topic__", "client_status,overall_type"), e_split("__topic__") ))Aturan DSL LOG lengkap adalah sebagai berikut:
# Pisahkan log. e_set("__topic__", "server_status") # Jika bidang content.servers tidak kosong, pisahkan log untuk membuat log dengan topik server_status. e_if(json_select(v("content"), "length(servers[*])"), e_compose( e_set("__topic__", "server_status,overall_type"), e_split("__topic__") )) # Jika bidang content.clients tidak kosong, pisahkan lebih lanjut log untuk membuat log dengan topik client_status. e_if(op_and(e_search("__topic__==overall_type"), json_select(v("content"), "length(clients[*])")), e_compose( e_set("__topic__", "client_status,overall_type"), e_split("__topic__") )) # Proses log overall_type. e_if(e_search("__topic__==overall_type"), e_compose( e_set("client_count", json_select(v("clients"), "length([*])", default=0)), e_set("server_count", json_select(v("servers"), "length([*])", default=0)) )) # Proses log server_status. e_if(e_search("__topic__==server_status"), e_compose( e_split("servers"), e_json("servers", depth=1) )) e_if(e_search("__topic__==overall_type"), e_drop_fields("servers")) # Proses log client_status. e_if(e_search("__topic__==client_status"), e_compose( e_split("clients"), e_json("clients", depth=1), e_drop_fields("clients") ))
Perbandingan Solusi
Solusi 1 secara logis berlebihan karena membuat log kosong dari log mentah dan kemudian menghapusnya. Namun, aturannya sederhana dan mudah dipelihara. Solusi ini direkomendasikan sebagai default.
Solusi 2 lebih efisien karena memeriksa bidang kosong sebelum pemisahan. Namun, aturannya sedikit lebih kompleks. Solusi ini hanya direkomendasikan untuk skenario tertentu, seperti ketika pemisahan awal mungkin menghasilkan banyak event tambahan.
Transformasi data JSON yang kompleks dengan objek array bertingkat banyak
Contoh ini menunjukkan cara memproses objek kompleks yang berisi array bertingkat banyak. Tujuannya adalah memisahkan setiap event login di array login_histories untuk setiap objek di array users menjadi event login terpisah.
Log Mentah
__source__: 192.0.2.1 __topic__: content:{ "users": [ { "name": "user1", "login_histories": [ { "date": "2019-10-10 0:0:0", "login_ip": "192.0.2.6" }, { "date": "2019-10-10 1:0:0", "login_ip": "192.0.2.6" }, { ...Informasi login lainnya... } ] }, { "name": "user2", "login_histories": [ { "date": "2019-10-11 0:0:0", "login_ip": "192.0.2.7" }, { "date": "2019-10-11 1:0:0", "login_ip": "192.0.2.9" }, { ...Informasi login lainnya... } ] }, { ...Lebih banyak pengguna... } ] }Log yang Diharapkan Setelah Pemisahan
__source__: 192.0.2.1 name: user1 date: 2019-10-11 1:0:0 login_ip: 192.0.2.6 __source__: 192.0.2.1 name: user1 date: 2019-10-11 0:0:0 login_ip: 192.0.2.6 __source__: 192.0.2.1 name: user2 date: 2019-10-11 0:0:0 login_ip: 192.0.2.7 __source__: 192.0.2.1 name: user2 date: 2019-10-11 1:0:0 login_ip: 192.0.2.9 ...Lebih banyak log...Solusi
Pisahkan dan perluas log berdasarkan
usersdi bidangcontent.e_split("content", jmes='users[*]', output='item') e_json("item",depth=1)Log yang telah diproses adalah:
__source__: 192.0.2.1 __topic__: content:{...Sama seperti yang ada di log mentah...} item: {"name": "user1", "login_histories": [{"date": "2019-10-10 0:0:0", "login_ip": "192.0.2.6"}, {"date": "2019-10-10 1:0:0", "login_ip": "192.0.2.6"}]} login_histories: [{"date": "2019-10-10 0:0:0", "login_ip": "192.0.2.6"}, {"date": "2019-10-10 1:0:0", "login_ip": "192.0.2.6"}] name: user1 __source__: 192.0.2.1 __topic__: content:{...Sama seperti yang ada di log mentah...} item: {"name": "user2", "login_histories": [{"date": "2019-10-11 0:0:0", "login_ip": "192.0.2.7"}, {"date": "2019-10-11 1:0:0", "login_ip": "192.0.2.9"}]} login_histories: [{"date": "2019-10-11 0:0:0", "login_ip": "192.0.2.7"}, {"date": "2019-10-11 1:0:0", "login_ip": "192.0.2.9"}] name: user2Selanjutnya, pisahkan dan perluas data berdasarkan
login_histories.e_split("login_histories") e_json("login_histories", depth=1)Log yang telah diproses adalah:
__source__: 192.0.2.1 __topic__: content: {...Sama seperti yang ada di log mentah...} date: 2019-10-11 0:0:0 item: {"name": "user2", "login_histories": [{"date": "2019-10-11 0:0:0", "login_ip": "192.0.2.7"}, {"date": "2019-10-11 1:0:0", "login_ip": "192.0.2.9"}]} login_histories: {"date": "2019-10-11 0:0:0", "login_ip": "192.0.2.7"} login_ip: 192.0.2.7 name: user2 __source__: 192.0.2.1 __topic__: content: {...Sama seperti yang ada di log mentah...} date: 2019-10-11 1:0:0 item: {"name": "user2", "login_histories": [{"date": "2019-10-11 0:0:0", "login_ip": "192.0.2.7"}, {"date": "2019-10-11 1:0:0", "login_ip": "192.0.2.9"}]} login_histories: {"date": "2019-10-11 1:0:0", "login_ip": "192.0.2.9"} login_ip: 192.0.2.9 name: user2 __source__: 192.0.2.1 __topic__: content: {...Sama seperti yang ada di log mentah...} date: 2019-10-10 1:0:0 item: {"name": "user1", "login_histories": [{"date": "2019-10-10 0:0:0", "login_ip": "192.0.2.6"}, {"date": "2019-10-10 1:0:0", "login_ip": "192.0.2.6"}]} login_histories: {"date": "2019-10-10 1:0:0", "login_ip": "192.0.2.6"} login_ip: 192.0.2.6 name: user1 __source__: 192.0.2.1 __topic__: content: {...Sama seperti yang ada di log mentah...} date: 2019-10-10 0:0:0 item: {"name": "user1", "login_histories": [{"date": "2019-10-10 0:0:0", "login_ip": "192.0.2.6"}, {"date": "2019-10-10 1:0:0", "login_ip": "192.0.2.6"}]} login_histories: {"date": "2019-10-10 0:0:0", "login_ip": "192.0.2.6"} login_ip: 192.0.2.6 name: user1Akhirnya, hapus bidang yang tidak relevan.
e_drop_fields("content", "item", "login_histories")Log yang telah diproses adalah:
__source__: 192.0.2.1 __topic__: name: user1 date: 2019-10-11 1:0:0 login_ip: 192.0.2.6 __source__: 192.0.2.1 __topic__: name: user1 date: 2019-10-11 0:0:0 login_ip: 192.0.2.6 __source__: 192.0.2.1 __topic__: name: user2 date: 2019-10-11 0:0:0 login_ip: 192.0.2.7 __source__: 192.0.2.1 __topic__: name: user2 date: 2019-10-11 1:0:0 login_ip: 192.0.2.9Aturan DSL LOG lengkap dapat ditulis sebagai berikut:
e_split("content", jmes='users[*]', output='item') e_json("item",depth=1) e_split("login_histories") e_json("login_histories", depth=1) e_drop_fields("content", "item", "login_histories")
Ringkasan: Untuk kebutuhan serupa, pertama-tama pisahkan log, lalu perluas data, dan akhirnya hapus bidang yang tidak relevan.