blackbird pluginを書こう第三弾ってことで、第二弾で細かく書けなかったところ、主に
- JobBaseの各メンバプロパティについて
- queueとか
- loggingとか
- 各基底クラス側で実装されている便利関数について
- こちらは落穂拾い的な内容になると思います
ではどどーんと逝きましょう。
About each member properties of JobBase
class
self.options
こちらは第二弾でも説明させていただきましたが、コンフィグファイルに記載した内容をkeyとvalueとして解釈して、
dictionary形式にしたものです。具体的には
[SECTION_NAME_IS_ANYTHING_OK]
hostname = hogehoge.com
hogehoge = fugafuga
みたいなコンフィグファイルがあったら、
self.options = {
'hostname': 'hogehoge.com',
'hogehoge': 'fugafuga'
}
みたいな感じのdictionaryが出来上がります。ここについては第二弾でも結構詳しく書いたつもりなので、
こんな感じです。もっとkwsk!ってのがあればコメントか僕宛にコンタクトを取ってもらえれば書かせていただこうかなと思います。
self.queue
MainのプロセスがThread間でメッセージをやりとりする用のQueueです。特に難しいことはしてなくって、
Python謹製のQueue.Queue
をそのまま使ってます。
なので、self.queue.put
メソッドはそのままQueue.Queue.put
を読んでいるものと同じだと考えてくださいまし。
notes:
putメソッドについてですが(プラグインを書く人は主にputメソッドを使うことになると思ってます)、
block
という引数があって自分がput操作をしているときは他のConsumer及びProducerからの操作を
blockするというものです。
しかし、こちらはひとつのItemに対してkey, clock, hostがかぶることはないという条件のもと、
block=False
を強く推奨しています。
self.logger
ロギング用のインスタンスです。このインスタンスはPython謹製のloggingモジュールを出力フォーマットだけ変更しただけのものになるので、
loggingモジュールのメソッドがそのまま使用可能です。
self.logger.debut('This is Debug log!! HOGEHOGE!!!!!!!!!!')
そのため上記のように書くことも可能です。ログの出力レベルですが、defaultではWARN
です(こちらはglobalセクションで変更が可能です)。
self.invalid_key_list
//今更ですがちょっとプロパティ名、ミスってるかなって気もしてますwww
//invalidじゃないなーって感じw ignoreとか??
こちらは、Itemのkeyがこのlistの中に存在している場合、Queueに入れないっていうブラックリストです。
たとえば、
class ConcreteJob(blackbird.plugins.base.JobBase):
def __init__(self, options, queue=None, logger=None):
super(ConcreteJob, self).__init__(options, queue, logger)
self.invalid_key_list = [
'host.IGNORE_KEY_NAME001',
'host.IGNORE_KEY_NAME002'
]
ってかけば、某memcachedのstats
コマンドのようなまるっと取ってくるってところに振り分け処理を書かずにロジックを別のメソッドに切り出すことが可能になります。
この場合、listに勝手に入れるだけではもちろんダメでございまして、
#..snip..
def filter_item(item):
if not item.data['key'] in self.invalid_key_list:
return item
def filter_items(items):
filtered_items = list()
for entry in items:
if not items.data.['key'] in self.invalid_key_list:
filtered_items.append(entry)
return filtered_items
的にいい感じで実装してもらえればと思います。
各基底クラス側で実装されている便利関数について
続きまして、各基底クラス側で実装されている便利関数についてです。
まぁ、正直多くはありませんが、それなりにプラグインづくりを手助けしてくれるとは思います。
blackbird.plugins.base.ValidatorBase.detect_hostname
名前の通りhostnameを取ってくるようなメソッドです。
低レイヤーな関数を使っているのですが(Pythonはこういうのがさらっと使えるのがいいですね)、その実すごいシンプルで、
return socket.getfqdn() or socket.gethostname() or 'localhost'
ってやってるだけです。
- socket.getfqdn()の結果があれば、それをそのままreturn
- なければsocket.gethostname() (short hostname、
hostname -s
の結果ですね)をreturn - それもダメなら
localhost
を文字列として返すってかんじですね。
使いドコロとしては、
class Validator(base.ValidatorBase):
def __init__(self):
self.__spec = None
@property
def spec(self):
self.__spec = (
"[{0}]".format(__name__),
"hostname = string(default={0})".format(self.detect_hostname()),
)
return self.__spec
こんなところですかね。ちなみにここは大先輩の提案により実装されたものでありまして、この場を借りましてありがとうございますですm(_ _)m
Timer context
Timer contextはwithでくくったコンテキスト内の処理時間を測定するcontextです。
僕たちはredisやmemcachedへのkeyの書き込みや読み込みに使ってratencyを測定してMetricにしてます。
使い方は普通のContextとなんにもかわんなくって、
import blackbird.plugins.base.Timer
with Timer() as timer:
for entry in xrange(0, 9):
print entry
return [timer.sec, timer.msec]
とかってやれば、timerクラスのsecプロパティが処理時間を秒(seconds)で返して、
msecプロパティが処理時間をミリ秒(mill seconds)で返してくれます。
About Blabckbird Exception
Exception(ここでいう本当の意味でのってのは、あなたのプラグインに予期せぬエラーが発生したときのExceptionって意味ですね)が
発生した時に予期せぬものなのか、それとも意図的にraise ValueError
のように発生させられたものなのかを区別するために、
独自のExceptionを実装してあります。
といっても、エラー文字列を指定してraiseするだけなので、ValueErrorとかとまったく同じ方法でraiseします。たとえば、
import blackbird.plugins.base.BlackbirdPluginError
try:
value = self.options['key']
except KeyError as exception:
raise blackbird.plugins.base.BlackbirdPluginError(
exception.__str__
)
とすることで、Exceptionを吐いた時の挙動をdebuggingしやすくします。
blackbird.plugins.base
モジュール側でやってることってこんなもんなんですが、
ここがわかんねーよとか、ここは違うんじゃねとか、こういうメソッドがbase側にも欲しいみたいなのが
ありましたらどんどん教えてもらえればなーと考えておりますm(_ _)m