全部产品
Search
文档中心

Simple Log Service:Transformasi data JSON kompleks

更新时间:Nov 09, 2025

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

    1. Pisahkan log mentah menjadi tiga log berdasarkan bidang topic: overall_type, client_status, dan server_status.

    2. Simpan informasi berbeda untuk nilai topic yang 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_service
  • Solusi

    1. 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...
      }
    2. Perluas konten JSON lapisan pertama dari bidang content, lalu hapus bidang content.

      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_service
    3. Untuk log dengan topik overall_type, hitung nilai untuk client_count dan server_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:  2
    4. Hapus bidang yang tidak diperlukan.

      e_if(e_search("__topic__==overall_type"), e_drop_fields("clients", "servers"))
    5. 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: green
    6. Bidang relevan yang perlu dipertahankan:

      e_if(e_search("__topic__==overall_type"), e_drop_fields("servers"))
    7. Anda dapat memisahkan lebih lanjut log dengan topik client_status dan 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: red
    8. Aturan 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_service
  • Solusi 1

    Setelah pemisahan awal, periksa apakah log dengan topik server_status dan client_status kosong. 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

    1. Pisahkan dan perluas log berdasarkan users di bidang content.

      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:  user2
    2. Selanjutnya, 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:  user1
    3. Akhirnya, 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.9
    4. Aturan 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.