SlideShare ist ein Scribd-Unternehmen logo
1 von 26
Downloaden Sie, um offline zu lesen
使い捨てコードの書き方	
  

    2012/08/25	
  
    @shiumachi	
  
お前誰よ?	
  
•  Sho	
  Shimauchi	
  	
  (	
  @shiumachi	
  )	
  
•  Cloudera	
  の問い合わせ担当	
  
•  技術質問から人生相談まで幅広く対応	
  
サポートに必要なもの	
  
•  Linux	
  コマンド	
  
   –  sed,	
  awk,	
  grep,	
  find,	
  sort	
  …	
  
   –  これで対応できるなら問題なし	
  
•  シェルスクリプト	
  
   –  for	
  i	
  in	
  `ls`	
  と	
  for	
  i	
  in	
  `seq	
  N`	
  があればなんとかなる	
  
•  正規表現	
  
   –  最強	
  
   –  最強と使いやすいかどうかは別問題	
  
•  軽量言語	
  
   –  上記3つで簡単に対応できない場合はこれを使う	
  
   –  特に集計処理とか入ると正規表現ブン回すより簡単だし
      再利用しやすい	
  
ユースケース	
  
•  ほとんどがパース・集計処理	
  
 –  ログ内の特定の文字をカウントする	
  
 –  シーケンスIDをピックアップし、ギャップを検出、カ
    ウントする	
  
 –  特定のIDを時系列で追跡し、クラスタ内での移動
    経路を追う	
  
•  その一回だけでしか使わないことが大半なの
   で、使い捨てのコードを書くことが多い	
  
ゴール	
  

とにかく楽に使い捨てたい	
  
 できれば再利用したい	
  
使い捨て方(1)	
  
  適当なディレクトリに適当に書く	
  
•  論外	
  
•  まず再利用不可能	
  
 –  場所がわからん	
  
 –  何に使ったかわからん	
  
使い捨て方(2)	
  
     git	
  で綺麗に管理する	
  
•  理想的だが案外面倒	
  
•  どのコードも目的が違うので、ドキュメントの
   整理・構造化も必要	
  
•  同一名で投げ込むことができず、名前空間の
   管理も必要	
  
使い捨て方(3)	
  gist	
  に突っ込んでおく	
  
•  多くの人が選んでいるであろう方法	
  
•  保存・管理の手間のコストパフォーマンスを考
   えるとこれがベスト	
  
テスト	
  
使い捨てコードだったらテストなんていらなく
ね?	
  
	
  


違います。楽するためにテスト必要	
  
xUnit/TDD	
  の(個人的な)弊害	
  
•  xUnit	
  
    –  クラス必須みたいに見えること	
  
    –  使い捨てコードでクラス必須って考えるだけでだるく
       なる(個人的に)	
  
•  TDD	
  
    –  入門書を読むと 100%	
  原則を守らないといけないよう
       に感じる	
  
nose	
  
•  色々便利な特徴はあるが、使い捨てコードに
   おける大きな特徴は2つ	
  
•  テストクラス作成が不要	
  
    –  test_*.py	
  としておいて、def	
  test_*:	
  というメソッド
       を書いておけば nosetests	
  で自動実行できる	
  
•  nose.tools	
  	
  
    –  eq_(a,	
  b)	
  だけでほぼ全てまかなえる	
  
テスト=ドキュメント	
  
•  頭の中で設計したら、ドキュメントじゃなくテス
   トとしてdumpしておくこと	
  
•  どうせパースだけなので、実際の入力データ
   から数行ひっぱってくれば十分	
  
•  網羅性を追求しない	
  
•  品質を追求しない	
  
•  実際に動かしてこけたら、その都度こけた入
   力をテストに追加	
  
エキPy	
  11	
  章より	
  
         テストのメリットは4つ	
  
1.    ソフトウェアのリグレッションの防止	
2.    コード、の品質の向上	
3.    最適で低レベルなドキュメントの提供	
4.    よりすばやく、信頼性の高いコードの生産
エキPy	
  11	
  章より	
  
          テストのメリットは4つ	
  
1.    ソフトウェアのリグレッションの防止	
2.    コード、の品質の向上	
3.    最適で低レベルなドキュメントの提供	
4.    よりすばやく、信頼性の高いコードの生産	
  

使い捨てコードにおいては3,4	
  だけで十分
テストもgistにアップロードする	
  
•  gistは一つのコンテンツに複数ファイルアップ
   ロード可能	
  
•  テストも一緒に突っ込んでおく	
  
 –  テストを読めば何をするコードか大体わかる	
  
 –  別の環境(Mac	
  -­‐>	
  Linux	
  など)でも動くかどうかテス
    ト可能	
  
サンプルコード	
  
•  hYps://gist.github.com/3460244	
  
実際の入力データ	
  
 hadoop	
  のネームノード(マスタ)のログ	
  
2012-­‐06-­‐04	
  13:30:59,197	
  INFO	
  org.apache.hadoop.hdfs.server.namenode.NameNode:	
  STARTUP_MSG:	
  	
  
/************************************************************	
  
STARTUP_MSG:	
  Starcng	
  NameNode	
  
STARTUP_MSG:	
  	
  	
  host	
  =	
  sho-­‐mba.local/192.168.100.130	
  
STARTUP_MSG:	
  	
  	
  args	
  =	
  []	
  
STARTUP_MSG:	
  	
  	
  version	
  =	
  0.20.2-­‐cdh3u4	
  
STARTUP_MSG:	
  	
  	
  build	
  =	
  git://ubuntu-­‐slave01/var/lib/jenkins/workspace/CDH3u4-­‐Full-­‐RC/build/cdh3/
hadoop20/0.20.2-­‐cdh3u4/source	
  -­‐r	
  214dd731e3bdb687cb55988d3f47dd9e248c5690;	
  compiled	
  by	
  'jenkins'	
  on	
  Mon	
  
May	
  	
  7	
  13:01:39	
  PDT	
  2012	
  
************************************************************/	
  
2012-­‐06-­‐04	
  13:30:59,680	
  INFO	
  org.apache.hadoop.metrics.jvm.JvmMetrics:	
  Inicalizing	
  JVM	
  Metrics	
  with	
  
processName=NameNode,	
  sessionId=null	
  
2012-­‐06-­‐04	
  13:30:59,683	
  INFO	
  org.apache.hadoop.hdfs.server.namenode.metrics.NameNodeMetrics:	
  Inicalizing	
  
NameNodeMeterics	
  using	
  context	
  object:org.apache.hadoop.metrics.spi.NullContext	
  
2012-­‐06-­‐04	
  13:30:59,788	
  INFO	
  org.apache.hadoop.hdfs.ucl.GSet:	
  VM	
  type	
  	
  	
  	
  	
  	
  	
  =	
  64-­‐bit	
  
2012-­‐06-­‐04	
  13:30:59,788	
  INFO	
  org.apache.hadoop.hdfs.ucl.GSet:	
  2%	
  max	
  memory	
  =	
  19.9175	
  MB	
  
2012-­‐06-­‐04	
  13:30:59,788	
  INFO	
  org.apache.hadoop.hdfs.ucl.GSet:	
  capacity	
  	
  	
  	
  	
  	
  =	
  2^21	
  =	
  2097152	
  entries	
  
2012-­‐06-­‐04	
  13:30:59,789	
  INFO	
  org.apache.hadoop.hdfs.ucl.GSet:	
  recommended=2097152,	
  actual=2097152	
  
2012-­‐06-­‐04	
  13:30:59,940	
  INFO	
  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:	
  fsOwner=sho	
  (auth:SIMPLE)	
  
2012-­‐06-­‐04	
  13:30:59,940	
  INFO	
  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:	
  supergroup=supergroup	
  
2012-­‐06-­‐04	
  13:30:59,940	
  INFO	
  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:	
  isPermissionEnabled=true	
  
2012-­‐06-­‐04	
  13:30:59,953	
  INFO	
  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:	
  
dfs.block.invalidate.limit=1000	
  
やりたいこと	
  
•  ログに出力されているログレベル(INFO,	
  
   WARN,	
  ERROR,	
  …)	
  を集計したい	
  
•  「それ awk	
  でできんじゃね?」とは言ってはい
   けない	
  
テストコード	
  
def test_parse():!
    input = "2012-06-04 13:31:07,065 INFO
org.apache.hadoop.net.NetworkTopology: Adding a new node: /
default-rack/127.0.0.1:50010"!
    input2 = "2012-06-04 13:31:05,466 WARN
org.apache.hadoop.util.PluginDispatcher: Unable to load
dfs.namenode.plugins plugins"!
    expected = 'INFO'!
    expected2 = 'WARN’!
    eq_(expected, parse(input))!
    eq_(expected2, parse(input2))!



入力データをベタ貼り	
  
サンプルコード	
  
def parse(line):!
    arr = line.strip().split() !
    log_level = arr[2]!
    return log_level!
	
  
テストは通るが実際には動かない	
  
2012-06-04 13:30:59,197 INFO org.apache.hadoop.hdfs.server.namenode.NameNode:
STARTUP_MSG: "
/************************************************************"
Traceback (most recent call last):"
  File "nn_parse.py", line 23, in <module>"
   main(sys.stdin)"
  File "nn_parse.py", line 11, in main"
   log_level = parse(line)"
  File "nn_parse.py", line 5, in parse"
   log_level = arr[2]"
IndexError: list index out of range	
  
失敗した行をそのままテストに追加	
  
def test_parse():!
    input = "2012-06-04 13:31:07,065 INFO
org.apache.hadoop.net.NetworkTopology: Adding a new node: /
default-rack/127.0.0.1:50010"!
    input2 = "2012-06-04 13:31:05,466 WARN
org.apache.hadoop.util.PluginDispatcher: Unable to load
dfs.namenode.plugins plugins"!
    input3 = "/
************************************************************"!
    expected = 'INFO'!
    expected2 = 'WARN'!
    expected3 = '_NULL'!
    eq_(expected, parse(input))!
    eq_(expected2, parse(input2))!
    eq_(expected3, parse(input3))	
  
失敗した行をそのままテストに追加	
  
def test_parse():!
    input = "2012-06-04 13:31:07,065 INFO
org.apache.hadoop.net.NetworkTopology: Adding a new node: /
default-rack/127.0.0.1:50010"!
    input2 = "2012-06-04 13:31:05,466 WARN
org.apache.hadoop.util.PluginDispatcher: Unable to load
dfs.namenode.plugins plugins"!
    input3 = "/
************************************************************"!
    expected = 'INFO'!
    expected2 = 'WARN'!
    expected3 = '_NULL'!
    eq_(expected, parse(input))!
    eq_(expected2, parse(input2))!
    eq_(expected3, parse(input3))	
  
コードもIndexErrorに対応	
  
def parse(line):!
    arr = line.strip().split()!
    try: !
        log_level = arr[2]!
    except:!
        log_level = '_NULL'!
    return log_level!
	
  
おしまい	
  

Weitere ähnliche Inhalte

Was ist angesagt?

Powershell 超絶基礎 勉強会 v1 (もっと新しいバージョンがあります)
Powershell 超絶基礎 勉強会 v1 (もっと新しいバージョンがあります)Powershell 超絶基礎 勉強会 v1 (もっと新しいバージョンがあります)
Powershell 超絶基礎 勉強会 v1 (もっと新しいバージョンがあります)
Tetsu Yama
 
SQLチューニング入門 入門編
SQLチューニング入門 入門編SQLチューニング入門 入門編
SQLチューニング入門 入門編
Miki Shimogai
 
System2 ajax
System2 ajaxSystem2 ajax
System2 ajax
Jun Chiba
 

Was ist angesagt? (17)

リーダブルコード 1.0'
リーダブルコード 1.0'リーダブルコード 1.0'
リーダブルコード 1.0'
 
名著『リーダブルコード』を解説者と一緒に読み解こう - 7章 制御フローを読みやすくする
名著『リーダブルコード』を解説者と一緒に読み解こう - 7章 制御フローを読みやすくする名著『リーダブルコード』を解説者と一緒に読み解こう - 7章 制御フローを読みやすくする
名著『リーダブルコード』を解説者と一緒に読み解こう - 7章 制御フローを読みやすくする
 
面白いセキュリティツール その2
面白いセキュリティツール その2面白いセキュリティツール その2
面白いセキュリティツール その2
 
リーダブルコードが良書だったのでまとめました
リーダブルコードが良書だったのでまとめましたリーダブルコードが良書だったのでまとめました
リーダブルコードが良書だったのでまとめました
 
システムパフォーマンス勉強会#4
システムパフォーマンス勉強会#4システムパフォーマンス勉強会#4
システムパフォーマンス勉強会#4
 
Powershell 超絶基礎 勉強会 v1 (もっと新しいバージョンがあります)
Powershell 超絶基礎 勉強会 v1 (もっと新しいバージョンがあります)Powershell 超絶基礎 勉強会 v1 (もっと新しいバージョンがあります)
Powershell 超絶基礎 勉強会 v1 (もっと新しいバージョンがあります)
 
PHPUnitTest勉強会スライド
PHPUnitTest勉強会スライドPHPUnitTest勉強会スライド
PHPUnitTest勉強会スライド
 
システムパフォーマンス勉強会#4
システムパフォーマンス勉強会#4システムパフォーマンス勉強会#4
システムパフォーマンス勉強会#4
 
SQLチューニング入門 入門編
SQLチューニング入門 入門編SQLチューニング入門 入門編
SQLチューニング入門 入門編
 
Powershell勉強会 v5 (こちらが最新です。)
Powershell勉強会 v5 (こちらが最新です。)Powershell勉強会 v5 (こちらが最新です。)
Powershell勉強会 v5 (こちらが最新です。)
 
PHPでAIプログラミングコンテスト準優勝するまでの軌跡
PHPでAIプログラミングコンテスト準優勝するまでの軌跡PHPでAIプログラミングコンテスト準優勝するまでの軌跡
PHPでAIプログラミングコンテスト準優勝するまでの軌跡
 
System2 ajax
System2 ajaxSystem2 ajax
System2 ajax
 
名著『リーダブルコード - より良いコードを書くためのシンプルで実践的なテクニック』を解説者と一緒に読み解こう
名著『リーダブルコード - より良いコードを書くためのシンプルで実践的なテクニック』を解説者と一緒に読み解こう名著『リーダブルコード - より良いコードを書くためのシンプルで実践的なテクニック』を解説者と一緒に読み解こう
名著『リーダブルコード - より良いコードを書くためのシンプルで実践的なテクニック』を解説者と一緒に読み解こう
 
システムパフォーマンス勉強会#5
システムパフォーマンス勉強会#5システムパフォーマンス勉強会#5
システムパフォーマンス勉強会#5
 
Racc でおてがる構文解析
Racc でおてがる構文解析Racc でおてがる構文解析
Racc でおてがる構文解析
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐ
 
リーダブルコードを読んだ後
リーダブルコードを読んだ後リーダブルコードを読んだ後
リーダブルコードを読んだ後
 

Ähnlich wie 使い捨て python コードの書き方

ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
Hiroh Satoh
 
PHPフレームワーク入門
PHPフレームワーク入門PHPフレームワーク入門
PHPフレームワーク入門
Sho A
 

Ähnlich wie 使い捨て python コードの書き方 (20)

CodeIgniter入門
CodeIgniter入門CodeIgniter入門
CodeIgniter入門
 
EmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤とEmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤と
 
EmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤とEmbulkとDigdagとデータ分析基盤と
EmbulkとDigdagとデータ分析基盤と
 
Chef
ChefChef
Chef
 
Nds#24 単体テスト
Nds#24 単体テストNds#24 単体テスト
Nds#24 単体テスト
 
DrupalでBDDテストを実施してみる①
DrupalでBDDテストを実施してみる①DrupalでBDDテストを実施してみる①
DrupalでBDDテストを実施してみる①
 
Tokyo r30 beginner
Tokyo r30 beginnerTokyo r30 beginner
Tokyo r30 beginner
 
Tokyo r38
Tokyo r38Tokyo r38
Tokyo r38
 
ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
 
Tdd
TddTdd
Tdd
 
PHPフレームワーク入門
PHPフレームワーク入門PHPフレームワーク入門
PHPフレームワーク入門
 
大規模ソフトウェア開発とテストの経験について
大規模ソフトウェア開発とテストの経験について大規模ソフトウェア開発とテストの経験について
大規模ソフトウェア開発とテストの経験について
 
Sourcecode Reading Workshop2010
Sourcecode Reading Workshop2010Sourcecode Reading Workshop2010
Sourcecode Reading Workshop2010
 
Gamedevenvstudy1
Gamedevenvstudy1Gamedevenvstudy1
Gamedevenvstudy1
 
[db tech showcase Tokyo 2014] B26: PostgreSQLを拡張してみよう by SRA OSS, Inc. 日本支社 高塚遥
[db tech showcase Tokyo 2014] B26: PostgreSQLを拡張してみよう  by SRA OSS, Inc. 日本支社 高塚遥[db tech showcase Tokyo 2014] B26: PostgreSQLを拡張してみよう  by SRA OSS, Inc. 日本支社 高塚遥
[db tech showcase Tokyo 2014] B26: PostgreSQLを拡張してみよう by SRA OSS, Inc. 日本支社 高塚遥
 
PHP基礎勉強会
PHP基礎勉強会PHP基礎勉強会
PHP基礎勉強会
 
C#勉強会
C#勉強会C#勉強会
C#勉強会
 
2020/11/19 Global AI on Tour - Toyama プログラマーのための機械学習入門
2020/11/19 Global AI on Tour - Toyama プログラマーのための機械学習入門2020/11/19 Global AI on Tour - Toyama プログラマーのための機械学習入門
2020/11/19 Global AI on Tour - Toyama プログラマーのための機械学習入門
 
はじめてのCodeIgniter
はじめてのCodeIgniterはじめてのCodeIgniter
はじめてのCodeIgniter
 
企業におけるSpring@日本springユーザー会20090624
企業におけるSpring@日本springユーザー会20090624企業におけるSpring@日本springユーザー会20090624
企業におけるSpring@日本springユーザー会20090624
 

使い捨て python コードの書き方

  • 1. 使い捨てコードの書き方   2012/08/25   @shiumachi  
  • 2. お前誰よ?   •  Sho  Shimauchi    (  @shiumachi  )   •  Cloudera  の問い合わせ担当   •  技術質問から人生相談まで幅広く対応  
  • 3. サポートに必要なもの   •  Linux  コマンド   –  sed,  awk,  grep,  find,  sort  …   –  これで対応できるなら問題なし   •  シェルスクリプト   –  for  i  in  `ls`  と  for  i  in  `seq  N`  があればなんとかなる   •  正規表現   –  最強   –  最強と使いやすいかどうかは別問題   •  軽量言語   –  上記3つで簡単に対応できない場合はこれを使う   –  特に集計処理とか入ると正規表現ブン回すより簡単だし 再利用しやすい  
  • 4. ユースケース   •  ほとんどがパース・集計処理   –  ログ内の特定の文字をカウントする   –  シーケンスIDをピックアップし、ギャップを検出、カ ウントする   –  特定のIDを時系列で追跡し、クラスタ内での移動 経路を追う   •  その一回だけでしか使わないことが大半なの で、使い捨てのコードを書くことが多い  
  • 5. ゴール   とにかく楽に使い捨てたい   できれば再利用したい  
  • 6. 使い捨て方(1)   適当なディレクトリに適当に書く   •  論外   •  まず再利用不可能   –  場所がわからん   –  何に使ったかわからん  
  • 7. 使い捨て方(2)   git  で綺麗に管理する   •  理想的だが案外面倒   •  どのコードも目的が違うので、ドキュメントの 整理・構造化も必要   •  同一名で投げ込むことができず、名前空間の 管理も必要  
  • 8. 使い捨て方(3)  gist  に突っ込んでおく   •  多くの人が選んでいるであろう方法   •  保存・管理の手間のコストパフォーマンスを考 えるとこれがベスト  
  • 9. テスト   使い捨てコードだったらテストなんていらなく ね?     違います。楽するためにテスト必要  
  • 10. xUnit/TDD  の(個人的な)弊害   •  xUnit   –  クラス必須みたいに見えること   –  使い捨てコードでクラス必須って考えるだけでだるく なる(個人的に)   •  TDD   –  入門書を読むと 100%  原則を守らないといけないよう に感じる  
  • 11. nose   •  色々便利な特徴はあるが、使い捨てコードに おける大きな特徴は2つ   •  テストクラス作成が不要   –  test_*.py  としておいて、def  test_*:  というメソッド を書いておけば nosetests  で自動実行できる   •  nose.tools     –  eq_(a,  b)  だけでほぼ全てまかなえる  
  • 12. テスト=ドキュメント   •  頭の中で設計したら、ドキュメントじゃなくテス トとしてdumpしておくこと   •  どうせパースだけなので、実際の入力データ から数行ひっぱってくれば十分   •  網羅性を追求しない   •  品質を追求しない   •  実際に動かしてこけたら、その都度こけた入 力をテストに追加  
  • 13.
  • 14. エキPy  11  章より   テストのメリットは4つ   1.  ソフトウェアのリグレッションの防止 2.  コード、の品質の向上 3.  最適で低レベルなドキュメントの提供 4.  よりすばやく、信頼性の高いコードの生産
  • 15. エキPy  11  章より   テストのメリットは4つ   1.  ソフトウェアのリグレッションの防止 2.  コード、の品質の向上 3.  最適で低レベルなドキュメントの提供 4.  よりすばやく、信頼性の高いコードの生産   使い捨てコードにおいては3,4  だけで十分
  • 16. テストもgistにアップロードする   •  gistは一つのコンテンツに複数ファイルアップ ロード可能   •  テストも一緒に突っ込んでおく   –  テストを読めば何をするコードか大体わかる   –  別の環境(Mac  -­‐>  Linux  など)でも動くかどうかテス ト可能  
  • 18. 実際の入力データ   hadoop  のネームノード(マスタ)のログ   2012-­‐06-­‐04  13:30:59,197  INFO  org.apache.hadoop.hdfs.server.namenode.NameNode:  STARTUP_MSG:     /************************************************************   STARTUP_MSG:  Starcng  NameNode   STARTUP_MSG:      host  =  sho-­‐mba.local/192.168.100.130   STARTUP_MSG:      args  =  []   STARTUP_MSG:      version  =  0.20.2-­‐cdh3u4   STARTUP_MSG:      build  =  git://ubuntu-­‐slave01/var/lib/jenkins/workspace/CDH3u4-­‐Full-­‐RC/build/cdh3/ hadoop20/0.20.2-­‐cdh3u4/source  -­‐r  214dd731e3bdb687cb55988d3f47dd9e248c5690;  compiled  by  'jenkins'  on  Mon   May    7  13:01:39  PDT  2012   ************************************************************/   2012-­‐06-­‐04  13:30:59,680  INFO  org.apache.hadoop.metrics.jvm.JvmMetrics:  Inicalizing  JVM  Metrics  with   processName=NameNode,  sessionId=null   2012-­‐06-­‐04  13:30:59,683  INFO  org.apache.hadoop.hdfs.server.namenode.metrics.NameNodeMetrics:  Inicalizing   NameNodeMeterics  using  context  object:org.apache.hadoop.metrics.spi.NullContext   2012-­‐06-­‐04  13:30:59,788  INFO  org.apache.hadoop.hdfs.ucl.GSet:  VM  type              =  64-­‐bit   2012-­‐06-­‐04  13:30:59,788  INFO  org.apache.hadoop.hdfs.ucl.GSet:  2%  max  memory  =  19.9175  MB   2012-­‐06-­‐04  13:30:59,788  INFO  org.apache.hadoop.hdfs.ucl.GSet:  capacity            =  2^21  =  2097152  entries   2012-­‐06-­‐04  13:30:59,789  INFO  org.apache.hadoop.hdfs.ucl.GSet:  recommended=2097152,  actual=2097152   2012-­‐06-­‐04  13:30:59,940  INFO  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:  fsOwner=sho  (auth:SIMPLE)   2012-­‐06-­‐04  13:30:59,940  INFO  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:  supergroup=supergroup   2012-­‐06-­‐04  13:30:59,940  INFO  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:  isPermissionEnabled=true   2012-­‐06-­‐04  13:30:59,953  INFO  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:   dfs.block.invalidate.limit=1000  
  • 19. やりたいこと   •  ログに出力されているログレベル(INFO,   WARN,  ERROR,  …)  を集計したい   •  「それ awk  でできんじゃね?」とは言ってはい けない  
  • 20. テストコード   def test_parse():!     input = "2012-06-04 13:31:07,065 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: / default-rack/127.0.0.1:50010"!     input2 = "2012-06-04 13:31:05,466 WARN org.apache.hadoop.util.PluginDispatcher: Unable to load dfs.namenode.plugins plugins"!     expected = 'INFO'!     expected2 = 'WARN’!     eq_(expected, parse(input))!     eq_(expected2, parse(input2))! 入力データをベタ貼り  
  • 21. サンプルコード   def parse(line):!     arr = line.strip().split() !     log_level = arr[2]!     return log_level!  
  • 22. テストは通るが実際には動かない   2012-06-04 13:30:59,197 INFO org.apache.hadoop.hdfs.server.namenode.NameNode: STARTUP_MSG: " /************************************************************" Traceback (most recent call last):" File "nn_parse.py", line 23, in <module>" main(sys.stdin)" File "nn_parse.py", line 11, in main" log_level = parse(line)" File "nn_parse.py", line 5, in parse" log_level = arr[2]" IndexError: list index out of range  
  • 23. 失敗した行をそのままテストに追加   def test_parse():!     input = "2012-06-04 13:31:07,065 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: / default-rack/127.0.0.1:50010"!     input2 = "2012-06-04 13:31:05,466 WARN org.apache.hadoop.util.PluginDispatcher: Unable to load dfs.namenode.plugins plugins"!     input3 = "/ ************************************************************"!     expected = 'INFO'!     expected2 = 'WARN'!     expected3 = '_NULL'!     eq_(expected, parse(input))!     eq_(expected2, parse(input2))!     eq_(expected3, parse(input3))  
  • 24. 失敗した行をそのままテストに追加   def test_parse():!     input = "2012-06-04 13:31:07,065 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: / default-rack/127.0.0.1:50010"!     input2 = "2012-06-04 13:31:05,466 WARN org.apache.hadoop.util.PluginDispatcher: Unable to load dfs.namenode.plugins plugins"!     input3 = "/ ************************************************************"!     expected = 'INFO'!     expected2 = 'WARN'!     expected3 = '_NULL'!     eq_(expected, parse(input))!     eq_(expected2, parse(input2))!     eq_(expected3, parse(input3))  
  • 25. コードもIndexErrorに対応   def parse(line):!     arr = line.strip().split()!     try: !         log_level = arr[2]!     except:!         log_level = '_NULL'!     return log_level!