LoginSignup
4
2

More than 5 years have passed since last update.

RustでJSONファイルを読み集計する

Last updated at Posted at 2019-04-28

コード全体は、このような感じ。解説はコードの後に書いてます。

use std::fs::File;
use std::io::{BufReader, BufRead};
use std::collections::HashMap;

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[derive(Debug, Serialize, Deserialize)]
struct LogItem {
    method: String,
    path: String,
    code: isize,
    size: isize,
}

fn main() -> Result<(), Box<std::error::Error>> {

    let mut scores = HashMap::new();
    let f = "/path/to/file";
    for result in BufReader::new(File::open(&f)?).lines() {
        let l = result?;
        let log: LogItem = serde_json::from_str(&l).unwrap();
        //println!("{:?}",log);
        let count = scores.entry(log.path).or_insert(0);
        *count += 1;
    }

    for(k, v) in &scores {
        println!("{} {}", k, v);
    }

    Ok(())
}

ここから動作環境とコード解説。

まず、apache-loggenでJSON形式で出力したファイルを用意する。

gem install apache-loggen
apache-loggen --limit=1000 --json > test.json

こんな感じのログが出力される。

{"host":"224.117.48.63","user":"-","method":"GET","path":"/category/software","code":200,"referer":"/item/electronics/2875","size":41,"agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11"}

Rustでは、こんな感じの構造体を用意する。集計したいものだけ用意すればいい。

struct LogItem {
    method: String,
    path: String,
    code: isize,
    size: isize,
}

ファイルから1行読むたびにJSONとしてパースする。改行が入り複数の行にまたがるJSONは、ちょっと苦労しそうだ。(どれぐらいあるのかな?)

let mut scores = HashMap::new();
let f = "/path/to/file";
for result in BufReader::new(File::open(&f)?).lines() {
    let l = result?;
    let log: LogItem = serde_json::from_str(&l).unwrap();
    //println!("{:?}",log);
    let count = scores.entry(log.path).or_insert(0);
    *count += 1;
}

最後に、Hashmapの中身をforループでハッシュマップのキーと値のペアを走査する。

for(k, v) in &scores {
    println!("{} {}", k, v);
}

追記ですが、reqwestでも簡単に書けますね。

extern crate reqwest;

use std::collections::HashMap;

fn main() -> Result<(), Box<std::error::Error>> {
    let resp: HashMap<String, String> = reqwest::get("https://httpbin.org/ip")?
        .json()?;
    //println!("{:#?}", resp);
    println!("{}", resp["origin"]);
    Ok(())
}
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2