Embulk 0.9.12でパーサーのエラーが追跡しやすくなった


2018年12月19日にリリースされたEmbulk 0.9.12では、パース失敗時にファイル名や行番号が参照できるようになったようです。[リリースノート](https://www.embulk.org/docs/release/release-0.9.12.html)。試してみましょう

ファイル名を出力するには、FileInput, Decoder, Parser全てのプラグインがEmbulk 0.9.12以降向けに作られている必要があるようです。現在確認できているのは次のプラグインです。

こちらにリストがないプラグインで対応しているかを知りたい人は[Twitter](https://twitter.com) で「EmbulkのXXXは、0.9.12以降で作られているか？」とツイートすると多分答えが返ってくると思います。(...たぶん)


| プラグイン | 種類      | 対応状況 |
|----------|-----------|---------|
| Azure   | FileInput | ○ |
| FTP   | FileInput | ○ |
| GCS   | FileInput | ○ |
| RiakCS   | FileInput | ○ |
| S3       | FileInput | ○ |
| SFTP   | FileInput | ○ |
| csv    | parser    | ○ |
| json    | parser    | ○ |
| jsonpath    | parser    | × |
| gz     | decoder   | ○ |

FileInput、Decoder、Parserプラグインの作者の方はプラグインのバージョンを上げましょう
(開発者向け情報参照)

```
% embulk example hoge
% embulk guess hoge/seed.yml -o config.yml
```

生成された`config.yml`のカラムをコメントにして定義したカラムとデータが不一致になるよう設定します。


```yaml
in:
  type: file
  path_prefix: /private/tmp/hoge/csv/sample_
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: LF
    type: csv
    delimiter: ','
    quote: '"'
    escape: '"'
    null_string: 'NULL'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: id, type: long}
    - {name: account, type: long}
    - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: purchase, type: timestamp, format: '%Y%m%d'}
#    - {name: comment, type: string} # <-- ここ
out: {type: stdout}
```

`embulk run config.yml`を実行します。

```
embulk run config.yml
2019-01-10 19:29:45.699 +0900: Embulk v0.9.12
...
2019-01-10 19:29:51.116 +0900 [INFO] (0001:transaction): {done:  0 / 1, running: 0}
2019-01-10 19:29:51.217 +0900 [WARN] (0015:task-0000): Skipped line /private/tmp/hoge/csv/sample_01.csv.gz:2 (Too many columns): 1,32864,2015-01-27 19:23:49,20150127,embulk
2019-01-10 19:29:51.218 +0900 [WARN] (0015:task-0000): Skipped line /private/tmp/hoge/csv/sample_01.csv.gz:3 (Too many columns): 2,14824,2015-01-27 19:01:23,20150127,embulk jruby
2019-01-10 19:29:51.218 +0900 [WARN] (0015:task-0000): Skipped line /private/tmp/hoge/csv/sample_01.csv.gz:4 (Too many columns): 3,27559,2015-01-28 02:20:02,20150128,"Embulk ""csv"" parser plugin"
hsato-mbp13:tmp hsato$  +0900 [WARN] (0015:task-0000): Skipped line /private/tmp/hoge/csv/sample_01.csv.gz:5 (Too many columns): 4,11270,2015-01-29 11:54:36,20150129,NULL
...
```

`Skipped line /private/tmp/hoge/csv/sample_01.csv.gz:2 (Too many columns): 1,32864...`のような行が出力されるようになりました。

`Skipped line ファイルのパス:行番号 (エラー内容): パースしたデータ` のようになるようです。


デバッグが捗りますね。


## 参考(実装の意図)

<blockquote class="twitter-tweet" data-conversation="none" data-lang="ja"><p lang="ja" dir="ltr">これの目的は「parseで失敗したときに問題のデータが含まれていたファイルをログから追跡できるようにすること」なので、このPRはそのための基盤の仕組み+組み込みプラグイン対応のみで、かつそのデータが対応済みParserまで渡ったとき初めて表示されます (parserしかparse失敗の文脈は知らないので)</p>&mdash; Dai MIKURUBE (@dmikurube) <a href="https://twitter.com/dmikurube/status/1083304676039086080?ref_src=twsrc%5Etfw">2019年1月10日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">記事ありがとうございます！ファイル名取得するためにはそうです。FileInputPluginは、OSSのS3、RiakCS、GCS、Azure、SFTP、FTPは対応済みです。<br>それらはEmbulk0.9.12以降が必須になります。それ以前のバージョンだとエラーになります。それぞれREADMEには追記済みです。</p>&mdash; Satoshi Akama (@oreradio) <a href="https://twitter.com/oreradio/status/1083319015894700032?ref_src=twsrc%5Etfw">2019年1月10日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 


## 開発者向け情報

<blockquote class="twitter-tweet" data-conversation="none" data-lang="ja"><p lang="ja" dir="ltr">おー、記事化ありがとうございます! 注意事項として、その config で使っている File-input プラグイン / Decoder プラグイン / Parser プラグインの全てが、今回の拡張に対応している必要があります (非対応の Decoder を間に挟むとファイル名情報が失われる)</p>&mdash; Dai MIKURUBE (@dmikurube) <a href="https://twitter.com/dmikurube/status/1083316443603644417?ref_src=twsrc%5Etfw">2019年1月10日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>