Pygmentsを使ってJekyll内記事のコードハイライトを実現する
あらすじ
Jekyllではデフォルトでコードにハイライトをつける事はできないようなので、Pygmentsという拡張を入れる。
環境
- Python 2.7.3 (2.6以上が必要)
- easy_install
easy_installはhttp://peak.telecommunity.com/dist/ez_setup.pyからDLし $ (sudo) python ez_setup.py
でインストールする。
※ 後に以下のようなエラーが出るかもしれない。
Liquid error: undefined method ‘Py_IsInitialized’ for RubyPython::Python:Module
これはRubyからPythonを呼びに行くRubypythonというライブラリの中で、libpython2.7.soというファイルを探しに行くが、見つからないとすぐあきらめるようなので? --enable-shared
オプションつけてのインストールが吉。
また、以下の様なエラーが出た場合、libpython2.7.so.1.0が見つからなくてpythonコマンドが実行できなくなった。
$ python
> python: error while loading shared libraries: libpython2.7.so.1.0: cannot open shared object file: No such file or directory$ ldd python
linux-vdso.so.1 => (0x00007fff9cf94000)
libpython2.7.so.1.0 => not found
libpthread.so.0 => /lib64/libpthread.so.0 (0x000000343d600000)
libdl.so.2 => /lib64/libdl.so.2 (0x000000343ce00000)
libutil.so.1 => /lib64/libutil.so.1 (0x0000003440200000)
libm.so.6 => /lib64/libm.so.6 (0x0000003665600000)
libc.so.6 => /lib64/libc.so.6 (0x000000343d200000)
/lib64/ld-linux-x86-64.so.2 (0x000000343ca00000)
/usr/libとか共有ライブラリが検索するように設定しているパスにシンボリックリンクを貼るか、LD_LIBRARY_PATHにパスを追加するか/etc/ld.so.conf.d/hogehoge.confを作ってパスを追加するかldconfigコマンドでパスを追加してからもう一回Pythonインストールする。
- CentOS 5.5にvirtualenvを入れて、Python2.7とFlaskの環境を作ったよ! - Bouldering & Com.
- 共有ライブラリのコンパイル時に必要な検索パスを追加する方法 - ドキ!丸ごと!夏目だらけの水泳大会
参考サイト
- Windowsでpygmentsを使ってコードハイライト
- pygmentsが原因でjekyllが重くなってた
- Swap out albino for pygments.rb
- tpw / css / syntax.css
手順
いきなりeasy_install。
$ easy_install Pygments
Searching for Pygments
Best match: pygments 1.5
Processing pygments-1.5-py2.7.egg
pygments 1.5 is already the active version in easy-install.pth
Installing pygmentize-script.py script to C:\Pythons\Python27\Scripts
Installing pygmentize.exe script to C:\Pythons\Python27\Scripts
Installing pygmentize.exe.manifest script to C:\Pythons\Python27\ScriptsUsing c:\pythons\python27\lib\site-packages\pygments-1.5-py2.7.egg
Processing dependencies for Pygments
Finished processing dependencies for Pygments
highlight hogeタグをテストするが、以下のようなエラーが表示されてしまった。
Liquid error: Bad file descriptor
Windowsでpygmentsを使ってコードハイライト によると、
C:\Ruby193\lib\ruby\gems\1.9.1\gems\albino-1.3.3\lib\albino.rbにパッチを当てる。
という事で albino.rb
にパッチをあてると解決するらしい。
確かに、Bundlerでインストールしたgemの中にしっかりと albino-1.3.3
がある。
……が。このalbinoはhighlightがあるたびにPygmentsを呼ぶようなのでこのまま使っていくと超重くなるらしい。
今現在gemでインストールできるjekyllはコードハイライトにalbinoっていう
モジュールを使ってみるみたいで、こいつはハイライトするコードブロックが
あるあるたびにpygamentsプロセスを立ち上げるらしく、それが原因で超重くなってたみたい。
それはできれば避けたい……。
Jekyllの修正
Swap out albino for pygments.rbを見ながら albino
を pygments.rb
に差し替えてやる。
差し替えが完了したらpygments.rbとその依存gemを取りに行くためbundle update。
$ bundle update
Fetching source index for http://rubygems.org/
Fetching source index for http://rubygems.org/
Using RedCloth (4.2.9)
Installing blankslate (3.1.2)
Using fast-stemmer (1.0.1)
Using classifier (1.3.3)
Using directory_watcher (1.4.1)
Installing ffi (1.0.11) with native extensions
Installing kramdown (0.14.0)
Using liquid (2.4.1)
Using syntax (1.0.0)
Installing maruku (0.6.1)
Installing rubypython (0.5.3)
Installing pygments.rb (0.2.13)
Using jekyll (0.11.2)
Using bundler (1.0.21)
Your bundle is updated! Use `bundle show [gemname]` to see where a bundled gem is installed.
これでまずは
{% highlight ruby %}
puts "hello world"
{% endhighlight %}
こういう表記が一応、liquid errorがでずに出力されるようになった。
puts "hello world"
world.each do |w|
w = "hoge"
end
色づけ
最後にハイライト。(記事上はもう色がついちゃってるんだけど、本来は全部黒いはず)これはtpw / css / syntax.cssからCSSを持ってくれば良い。このsyntax.cssの内容を JEKYLL_HOME\assets\themes\twitter\bootstrap\css\bootstrap.min.css
に追記する。
これでOK!
JekyllをGitHub Pagesに上げるための準備
GitHub Pagesに登録
GitHubより New Repository
を選択。
Repository Name
を GitHubのID.github.com
と入力しリポジトリ作成。
前回の記事で作成していたJekyll Bootstrapのプッシュ先を追加し、プッシュ。
$ git remote add origin git@github.com:gosyujin/gosyujin.github.com.git
$ git push -u origin master
http://gosyujin.github.com にアクセスしても多分404なので。気長に待つ。
その間にSite Urlに上のUrlでも入れとく。
そんなこんなでサイトが表示されるようになっているはず。(メールが来たら?)
色々な設定
まずは _config.yml
。
デフォルトのmarkdownパーサの maruku
は日本語をうまくパースしてくれないみたいなので(日本語でリスト表記ができなかった)、 kramdown
に変更する。以下の記述を追加。
markdown: kramdown
他、タイトルや名前、TwitterIDなどを編集。
title : kk_Atakaの日記
tagline:
author :
name : kk_Ataka
email : kk_ataka@ring.skr.jp
github : gosyujin
twitter : kk_Ataka
feedburner : feedname
production_urlをGitHub Pagesに。
production_url : http://gosyujin.github.com
ここから先はJekyll Bootstrapでインストールした時に入ったコメント機能とかアクセス解析の設定。
コメント機能
デフォルトでは DISQUS
というツールを使用している。まずDISQUS - Elevating the discussionでユーザ登録をする必要がある。(TwitterID等でも可能)
アカウントを作ったら自分のサイトを登録。
ここで入力する shortname
を控えておく。
_config.yml
にさっきの shortname
を記述する。 provider
もDISQUSになっている事を確認する。
comments :
provider : disqus
disqus :
short_name : kkataka
(略)
これでいけるはず。(だめならUniversalコードを _includes/JB/comments-providers/disqus
に貼り付けてみる?)
自分のサイトにコメントが書き込まれると、こんな感じでDISQUSに表示される。
現時点で、DISQUSのコメント欄を日本語にするには Admin => Settings => Disqus 2012
のチェックを外す。DISQUS 2012テーマ(?)はまだ日本語に対応していないらしい。また、 Language
はJapaneseにしておくこと。
アクセス解析
デフォルトでは Google Analytics
を使用している。トラッキング ID(UA-xxxxxxxx-x)を控えて _config.yml
に記述する。
analytics :
provider : google
google :
tracking_id : 'UA-xxxxxxxx-x'
次はレイアウトの変更とかツイートボタン設置とか。
JekyllとJekyll Bootstrapでかんたん静的サイト生成…するための準備
あらすじ
- はてな記法、綺麗に出力できて今までお気に入りだったんだけど、欠点として、はてなでしか使わないという問題が
- 他にも文章書く時にreSTとかMarkdownを使うと捗るが、結局アウトプットするのは個人でははてなが多い……*1
- そもそもはてな記法は基本はてなじゃなきゃ見れない
- なら最初から…?
うーん。他の記法使う時がきたのか。
Jekyllとは
Jekyll is a simple, blog aware, static site generator.
https://github.com/mojombo/jekyll/wiki
静的サイトのジェネレーターなのね。 HTML, Markdown, textile なんでもござれ。
参考サイト
いきなり動かす
本来は決まったディレクトリを作ったり、コンフィグファイルを作ったり、レイアウトファイルを作ったりしていく……のだけど、Jekyll Bootstrapを使えばいきなりフルセットで動かす事ができる。
取得はGitで。
$ git clone http://github.com/plusjade/jekyll-bootstrap.git JEKYLL_HOME
JekyllはBundlerでインストールするので移動してGemfileを作成。そしてjekyllコマンドで実行!
$ cd JEKYLL_HOME $ vi Gemfile $ cat Gemfile source :rubygems source "http://rubygems.org" gem 'jekyll' gem 'RedCloth' $ bundle install --path vendor/bundle $ bundle exec jekyll --server
これで、http://localhost:4000 にアクセスしてみると超カッコいいサンプルページが出来上がっている。CentOSは以上。
ハマり for Windows
ところで、Windows XPで同じ事やっても_site下に静的ファイルが全然できなかった。……まあ、そもそもXP使うなって話?
結果としては、RedCloth-4.2.9-x86-mingw32直下のspecディレクトリを削除したら生成されるようになった。静的ファイル生成の流れを追っていくと、
- jekyll/bin/jekyll内でsite.processメソッドが呼ばれている
- jekyll/lib/jekyll/site.rbのprocessメソッドからread,readからread_directoriesメソッドが呼ばれている
- read_directoriesメソッドは以下のようになっている
def read_directories(dir = '') base = File.join(self.source, dir) entries = Dir.chdir(base) { filter_entries(Dir['*']) } self.read_posts(dir) entries.each do |f| f_abs = File.join(base, f) f_rel = File.join(dir, f) if File.directory?(f_abs) next if self.dest.sub(/\/$/, '') == f_abs read_directories(f_rel) elsif !File.symlink?(f_abs) first3 = File.open(f_abs) { |fd| fd.read(3) } if first3 == "---" #\yaml!/ # file appears to have a YAML header so process it as a page pages << Page.new(self, self.source, dir, f) else # otherwise treat it as a static file static_files << StaticFile.new(self, self.source, dir, f) end end end end
- 読み込むファイルをputs して眺めていると、\yaml!/のところでRedCloth-4.2.9-x86-mingw32\spec\fixtures\basic.ymlを呼んだ瞬間止まっている模様……
- まあ、specファイルだしなくてもいいよね? 削除、で、動いたという事で*2
で、動かす(Windows)。
$ be jekyll --server Configuration from C:/HOGE/jekyll/_config.yml Auto-regenerating enabled: C:/HOGE/project/jekyll -> C:/HOGE/project/jekyll/_site [2012-09-12 23:50:51] regeneration: 983 files changed [2012-09-12 23:50:54] INFO WEBrick 1.3.1 [2012-09-12 23:50:54] INFO ruby 1.9.2 (2011-07-09) [i386-mingw32] [2012-09-12 23:50:54] INFO WEBrick::HTTPServer#start: pid=5944 port=4000 ___________________________________________________________________________ | Maruku tells you: +--------------------------------------------------------------------------- | Unclosed span (waiting for ["_"]) | --------------------------------------------------------------------------- | Included file 'sig.markdown' not found in _includes directoryEOF | -------------------------------------------------------------|-------------- | +--- Byte 61 | Shown bytes [0 to 61] of 61: | >Included file 'sig.markdown' not found in _includes directory | | At line 2 | text |Included file 'sig.markdown' not found in _includes directory| | empty --> || | text |This _is_ cool| | | | Elements read in span: | | Current string: | "includes directory" +--------------------------------------------------------------------------- !C:/HOGE/project/jekyll/vendor/bundle/ruby/1.9.1/gems/maruku-0.6.0/lib/maruku/errors_management.rb:49:in `maruku_error' !C:/HOGE/project/jekyll/vendor/bundle/ruby/1.9.1/gems/maruku-0.6.0/lib/maruku/input/parse_span_better.rb:222:in `read_span' !C:/HOGE/project/jekyll/vendor/bundle/ruby/1.9.1/gems/maruku-0.6.0/lib/maruku/input/parse_span_better.rb:423:in `read_em' !C:/HOGE/project/jekyll/vendor/bundle/ruby/1.9.1/gems/maruku-0.6.0/lib/maruku/input/parse_span_better.rb:202:in `read_span' !C:/HOGE/project/jekyll/vendor/bundle/ruby/1.9.1/gems/maruku-0.6.0/lib/maruku/input/parse_span_better.rb:46:in `parse_span_better' \___________________________________________________________________________
エラーは出てるけど、これで http://localhost:4000にアクセスするとページが見れる!
sig ... 署名? あんまりよくないけど、空っぽでも存在さえすれば怒られないっぽい。
Fluentdの自作プラグインがロードできないのでソースの中身を追ってみる…
あらすじ
前回までに簡単なプラグインを作成する事はできた。
次はプラグインをGem化しようかなと思って色々いじってたら、実行時になんかうまくプラグインが読めない……。なんで?
今できてる事とできてない事
BundlerでFluentdをインストールし、
$ bundle exec fluentd -c /hoge/fluent.conf -p /hoge/plugin
を実行した時……
- gem installで入れたfluentdのプラグインはちゃんとロードできる
- Gemにしちゃえばロードできる
- プラグインディレクトリ直下(-p /hoge/plugin)にササッと作ってみたプラグインもロードでき、動いた
- 直下に放り込めばロードできる
/hoge/plugin └in_hoge.rb # これはロードできる
- gem未満、ササッと作った以上のプラグインがロードできない
- fluent-pluginっぽいディレクトリ構成にした程度のもの。まだローカルに置いてあるだけでgemには成り切れていない
/hoge/plugin ├in_hoge.rb # これはロードできる └fluent-plugin-hogehoge ├lib │└fluent │ └plugin │ └in_hogehoge.rb # これがロードできない ├fluent-plugin-hogehoge.gemspec └他
調査結果と(暫定)解決策
fluentdのプラグインロード順番
fluentdコマンドを実行すると、 なんやかんやあって プラグインをロードしにいく。ソースは$FLUENTD_HOME/lib/fluent/plugin.rb
- $FLUENTD_HOME/lib/fluent/plugin/直下のrbファイルをロードする
- in_exec.rbとか
- gem_pluginをロードする
- これは今回空だった
- /etc/fluent/plugin/直下のrbファイルをロードする
- デフォルトのプラグイン置き場
- デフォルトの設定は$FLUENTD_HOME/lib/fluent/env.rbに定義されている
- オプションで-p /hoge/pluginを指定していた場合、/hoge/plugin直下のrbファイルもロードする
- また、-pオプションは複数指定できる
- fluent.confに定義されている
- なかった場合はもう少し色々な場所の探索にチャレンジする
- $LOAD_PATHと、gem installしたディレクトリ直下のどこかにlib/fluent/plugin/
_ が存在するか.rb
- $LOAD_PATHと、gem installしたディレクトリ直下のどこかにlib/fluent/plugin/
解決策
- fluentd自体の$LOAD_PATHに追加
- 本体に毎回修正かけるの?
- in_hogehoge.rbをロードしてくれる場所へコピー(デフォルトプラグイン(/etc/fluent/plugin)など)
- コピペ?
- さっさと作ってgem installできるようにもっていく
- うーん…
- オプション-pを複数指定する
- 上の場合は -p /hoge/plugin -p /hoge/plugin/fluent-plugin-hogehoge/lib/fluent/plugin としてやればよい
- fluentd本体でわざわざlib/fluent/plugin下を探すようにコーディングされてるのにこんな指定の仕方するものかな? 何か違う気がする……下みたいに未完成のプラグインが増えていくとオプションガンガン長くなっていく?
- 上の場合は -p /hoge/plugin -p /hoge/plugin/fluent-plugin-hogehoge/lib/fluent/plugin としてやればよい
/hoge/plugin ├in_hoge.rb ├fluent-plugin-hogehoge │└lib │ └fluent │ └plugin │ └in_hogehoge.rb ├fluent-plugin-hogehoge2 │└lib │ └fluent │ └plugin │ └in_hogehoge2.rb └fluent-plugin-hogehoge3 └lib └fluent └plugin └in_hogehoge3.rb
以下、調査ログ。
調査ログ
セットアップをすると指定したディレクトリにconfigファイルとpluginディレクトリができる。
$ fluentd -s fluentd-hoge Installed fluentd-hoge/fluent.conf. $ ls fluentd-hoge/ fluent.conf plugin
pluginディレクトリにそのままプラグイン(rbファイル)を入れておくと、起動時に読み込まれる。
bundle gemコマンドを使ってプラグインを作っていく
$ cd plugin # プラグインを作るからとりあえずpluginディレクトリに移動する $ bundle gem fluent-plugin-hogehoge create fluent-plugin-hogehoge/Gemfile create fluent-plugin-hogehoge/Rakefile create fluent-plugin-hogehoge/LICENSE create fluent-plugin-hogehoge/README.md create fluent-plugin-hogehoge/.gitignore create fluent-plugin-hogehoge/fluent-plugin-hogehoge.gemspec create fluent-plugin-hogehoge/lib/fluent-plugin-hogehoge.rb create fluent-plugin-hogehoge/lib/fluent-plugin-hogehoge/version.rb Initializating git repo in /略/fluent-hoge/plugin/fluent-plugin-hogehoge
なんかいろいろ出来たがちょっとルールがあるようなので整形していく。公式サイトより
Installing custom plugins
To install a plugin, put a ruby script to /etc/fluent/plugin directory.
Or you can create gem package that includes lib/fluent/plugin/
http://fluentd.org/doc/devel.html_ .rb file.
TYPE is in for input plugins, out for output plugins and buf for buffer plugins.
It’s like lib/fluent/plugin/out_mail.rb.
The packaged gem can be distributed and installed using RubyGems.
See Searching plugins.
- プラグインは/etc/fluent/pluginにインストールするといいよ
- また、-pオプションを指定すればfluent-hoge/plugin下も呼んでくれる
- Gem packageを作る場合はパッケージの下にlib/fluent/plugin/
_ .rbって名前にしておいてね - 他の方が作ったプラグイン@GitHubを見ていると確かにそうなっていた!
はinputプラグインならin、outputプラグインならoutといったように - このルールは後ほど効いてくる
ってわけでディレクトリはこんな構成に。
fluent-hoge/ ├(略) ├fluent.conf └plugin/ … (1) └fluent-plugin-hogehoge ├Gemfile # この辺はほぼいじってない ├LICENSE # この辺はほぼいじってない ├README.md # この辺はほぼいじってない ├Rakefile # この辺はほぼいじってない ├fluent-plugin-inputs.gemspec # この辺はほぼいじってない └lib/ └fluent/ └plugin/ └in_inputs.rb
プラグインも作成。ただ{"plugin"=>"yes"}を出力しまくるだけのソース。
class FluPluGem < Fluent::Input Fluent::Plugin.register_input("inputs", self) def initialize super end def configure(conf) super end def start puts "a starts" @thread = Thread.new(&method(:run)) end def run loop do Fluent::Engine.emit("debugx.debug", Fluent::Engine.now, {"plugin" => "yes"}) sleep(2) end end end
fluent.confにプラグインを追加。
<source> type inputs </source>
この状態で起動!
/usr/local/bin/fluentd -c /略/fluent-hoge/fluent.conf -p /略/fluent-hoge/plugin/ 2012-09-07 19:57:48 +0900: starting fluentd-0.10.25 2012-09-07 19:57:48 +0900: reading config file path="/略/fluent-hoge/fluent.conf" 2012-09-07 19:57:48 +0900: adding source type="forward" 2012-09-07 19:57:48 +0900: adding source type="inputs" 2012-09-07 19:57:48 +0900: config error file="/略/fluent-hoge/fluent.conf" error="Unknown input plugin 'inputs'. Run 'gem search -rd fluent-plugin' to find plugins" 2012-09-07 19:57:48 +0900: process finished code=256 2012-09-07 19:57:48 +0900: process died within 1 second. exit.
失敗した…。inputsっていうプラグインなぞないって言われた。でも、プラグイン本体(in_inputs.rb)をplugin直下(ディレクトリ構成の(1)の部分)に持ってくると…
/usr/local/bin/fluentd -c /略/fluent-hoge/fluent.conf -p /略/fluent-hoge/plugin/ 2012-09-07 20:02:28 +0900: starting fluentd-0.10.25 2012-09-07 20:02:28 +0900: reading config file path="/略/fluent-hoge/fluent.conf" 2012-09-07 20:02:28 +0900: adding source type="forward" 2012-09-07 20:02:28 +0900: adding source type="inputs" 2012-09-07 20:02:28 +0900: adding source type="thread" 2012-09-07 20:02:28 +0900: adding source type="tail" 2012-09-07 20:02:28 +0900: 'pos_file PATH' parameter is not set to a 'tail' source. 2012-09-07 20:02:28 +0900: this parameter is highly recommended to save the position to resume tailing. 2012-09-07 20:02:28 +0900: adding match pattern="stdd.std" type="file" 2012-09-07 20:02:28 +0900: adding match pattern="devid.devid" type="file" 2012-09-07 20:02:28 +0900: adding match pattern="jenkins.**" type="file" 2012-09-07 20:02:28 +0900: adding match pattern="debug.**" type="stdout" 2012-09-07 20:02:28 +0900: listening fluent socket on 0.0.0.0:24224
起動した…。
Or you can create gem package that includes lib/fluent/plugin/
_ .rb file.
この文の認識が間違ってるのかなー?
よくわからないので本丸を攻めてみる。pluginの処理を記述しているのはそのものplugin.rb、また、それを呼ぼうとしているはsupervisor.rb,engine.rbあたりっぽい。
- fluentd/lib/fluent/plugin.rb at master · fluent/fluentd · GitHub
- fluentd/lib/fluent/engine.rb at master · fluent/fluentd · GitHub
- fluentd/lib/fluent/supervisor.rb at master · fluent/fluentd · GitHub
ロードしているのはplugin内だろうと思い、いろいろ出力してみる。
def load_plugins dir = File.join(File.dirname(__FILE__), "plugin") puts "!load_plugins:#{dir}" load_plugin_dir(dir) load_gem_plugins end
def load_plugin_dir(dir) dir = File.expand_path(dir) puts "!load_plugin_dir:#{dir}" Dir.entries(dir).sort.each {|fname| puts "!load_plugin_dir:#{fname}" if fname =~ /\.rb$/ require File.join(dir, fname) end } nil end
private def load_gem_plugins return unless defined? Gem plugins = Gem.find_files('fluent_plugin') puts "!load_gem_plugins:#{plugins}" plugins.each {|plugin| begin load plugin rescue ::Exception => e msg = "#{plugin.inspect}: #{e.message} (#{e.class})" $log.warn "Error loading Fluent plugin #{msg}" end } end
def try_load_plugin(name, type) puts "!try_load_plugin:#{name}, #{type}" case name when 'input' path = "fluent/plugin/in_#{type}" when 'output' path = "fluent/plugin/out_#{type}" when 'buffer' path = "fluent/plugin/buf_#{type}" else return end # prefer LOAD_PATH than gems files = $LOAD_PATH.map {|lp| puts "!try_load_plugin:#{lp}" lpath = File.join(lp, "#{path}.rb") File.exist?(lpath) ? lpath : nil }.compact unless files.empty? # prefer newer version require files.sort.last return end # search gems if defined?(::Gem::Specification) && ::Gem::Specification.respond_to?(:find_all) specs = Gem::Specification.find_all {|spec| spec.contains_requirable_file? path } # prefer newer version specs = specs.sort_by {|spec| spec.version } if spec = specs.last spec.require_paths.each {|lib| file = "#{spec.full_gem_path}/#{lib}/#{path}" require file } end
実行結果はこうなる。
$ /usr/local/bin/fluentd -c /略/fluent-hoge/fluent.conf -p /略/fluent-hoge/plugin/ 2012-09-07 19:37:32 +0900: starting fluentd-0.10.25 2012-09-07 19:37:32 +0900: reading config file path="/略/fluent-hoge/fluent.conf"
→はじめはfluent本体のpluginを呼んでる。
!load_plugins:/usr/local/lib/ruby/gems/1.9.1/gems/fluentd-0.10.25/lib/fluent/plugin !load_plugin_dir:/usr/local/lib/ruby/gems/1.9.1/gems/fluentd-0.10.25/lib/fluent/plugin !load_plugin_dir:. !load_plugin_dir:.. !load_plugin_dir:buf_file.rb !load_plugin_dir:buf_memory.rb !load_plugin_dir:buf_zfile.rb !load_plugin_dir:in_exec.rb !load_plugin_dir:in_forward.rb !load_plugin_dir:in_gc_stat.rb !load_plugin_dir:in_http.rb !load_plugin_dir:in_object_space.rb !load_plugin_dir:in_status.rb !load_plugin_dir:in_stream.rb !load_plugin_dir:in_syslog.rb !load_plugin_dir:in_tail.rb !load_plugin_dir:out_copy.rb !load_plugin_dir:out_exec.rb !load_plugin_dir:out_exec_filter.rb !load_plugin_dir:out_file.rb !load_plugin_dir:out_forward.rb !load_plugin_dir:out_null.rb !load_plugin_dir:out_roundrobin.rb !load_plugin_dir:out_stdout.rb !load_plugin_dir:out_stream.rb !load_plugin_dir:out_test.rb
→gemはない。
!load_gem_plugins:[]
→ここから他のpluginディレクトリ。まずは/etc/fluent/plugin。
!load_plugin_dir:/etc/fluent/plugin !load_plugin_dir:. !load_plugin_dir:..
→そして-pオプションで指定したディレクトリ。
!load_plugin_dir:/略/fluent-hoge/plugin !load_plugin_dir:. !load_plugin_dir:.. !load_plugin_dir:fluent-plugin-hogehoge !load_plugin_dir:simple_thread_plugin.rb
あれ?ディレクトリの上さらっと舐めるだけ?
ここからtypeがaddされている。みつかったものは特に何も表示されず次へ次へ……。
2012-09-07 20:16:24 +0900: adding source type="forward" 2012-09-07 20:16:24 +0900: adding source type="thread" 2012-09-07 20:16:24 +0900: adding source type="tail" 2012-09-07 20:16:24 +0900: 'pos_file PATH' parameter is not set to a 'tail' source. 2012-09-07 20:16:24 +0900: this parameter is highly recommended to save the position to resume tailing.
で、今回見つかってないtypeが出てくると、try_load_pluginが呼ばれる。
2012-09-07 20:16:24 +0900: adding source type="inputs" !try_load_plugin:input, inputs !try_load_plugin:/usr/local/lib/ruby/gems/1.9.1/gems/http_parser.rb-0.5.3/lib !try_load_plugin:/usr/local/lib/ruby/gems/1.9.1/gems/msgpack-0.4.7/lib !try_load_plugin:/usr/local/lib/ruby/gems/1.9.1/gems/yajl-ruby-1.1.0/lib !try_load_plugin:/usr/local/lib/ruby/gems/1.9.1/gems/iobuffer-1.1.2/lib !try_load_plugin:/usr/local/lib/ruby/gems/1.9.1/gems/cool.io-1.1.0/lib !try_load_plugin:/usr/local/lib/ruby/gems/1.9.1/gems/http_parser.rb-0.5.3/lib !try_load_plugin:/usr/local/lib/ruby/gems/1.9.1/gems/fluentd-0.10.25/lib !try_load_plugin:/usr/local/lib/ruby/gems/1.9.1/gems/json-1.7.4/lib !try_load_plugin:/usr/local/lib/ruby/site_ruby/1.9.1 !try_load_plugin:/usr/local/lib/ruby/site_ruby/1.9.1/i686-linux !try_load_plugin:/usr/local/lib/ruby/site_ruby !try_load_plugin:/usr/local/lib/ruby/vendor_ruby/1.9.1 !try_load_plugin:/usr/local/lib/ruby/vendor_ruby/1.9.1/i686-linux !try_load_plugin:/usr/local/lib/ruby/vendor_ruby !try_load_plugin:/usr/local/lib/ruby/1.9.1 !try_load_plugin:/usr/local/lib/ruby/1.9.1/i686-linux !try_load_plugin:/usr/local/lib/ruby/gems/1.9.1/gems/fluentd-0.10.25/lib 2012-09-07 20:16:24 +0900: config error file="/略/fluent-hoge/fluent.conf" error="Unknown input plugin 'inputs'. Run 'gem search -rd fluent-plugin' to find plugins" 2012-09-07 20:16:24 +0900: process finished code=256 2012-09-07 20:16:24 +0900: process died within 1 second. exit.
まずプラグインの種類によって読み込まれるパスとファイル名が決まるみたい。
case name when 'input' path = "fluent/plugin/in_#{type}" when 'output' path = "fluent/plugin/out_#{type}" when 'buffer' path = "fluent/plugin/buf_#{type}" else return end
Or you can create gem package that includes lib/fluent/plugin/
_ .rb file.
がここで効いてくるわけか。
そしたら$LOAD_PATHの中にfluent/plugin/in_inputs.rbがないか探しに行ってる。そしてそこにもなかった場合、インストールしたGemの中を探す。
# prefer LOAD_PATH than gems files = $LOAD_PATH.map {|lp| puts "!try_load_plugin:#{lp}" lpath = File.join(lp, "#{path}.rb") File.exist?(lpath) ? lpath : nil }.compact unless files.empty? # prefer newer version require files.sort.last return end # search gems if defined?(::Gem::Specification) && ::Gem::Specification.respond_to?(:find_all) specs = Gem::Specification.find_all {|spec| spec.contains_requirable_file? path } # prefer newer version specs = specs.sort_by {|spec| spec.version } if spec = specs.last spec.require_paths.each {|lib| file = "#{spec.full_gem_path}/#{lib}/#{path}" require file } end
っていう流れになっているらしい。
うーんGemで入れたら読めるんだけどなー。
Git add, commitをした時、中でどんな事が起こっているのか
あらすじ
いまだにファイルがどういうタイミングでリポジトリ、インデックス、ワーキングエリア間を行き来しているのかわからんので色々調べてみることに。
参考資料、サイト
やってみる
まずは、空のREADMEファイルを作ってFirst commit。
$ git init Initialized empty Git repository in /tmp/repos/.git/ $ touch README $ git add README $ git commit -m "first commit" [master (root-commit) b0d99b3] first commit 0 files changed create mode 100644 README $ git log --graph --date-order --all --date=short -C -M --pretty=format:"%h"\ %t\ %ad\ %Cblue%cn%Creset\ %Cgreen%d%Creset\ %s * b0d99b3 543b9be 2012-08-29 kk_Ataka (HEAD, master) first commit
色々確認
ゆっくり
READMEを編集してみる。
$ echo "このリポジトリはテスト用です" > README $ git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: README # no changes added to commit (use "git add" and/or "git commit -a")
addしたとき
ここでREADMEファイルをadd。
$ git add README $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: README #
再度、色々確認。
リポジトリにコミットされているREADME e69de29 の他にde7e855 というオブジェクトがステージされている。おまけに.git/objectsの下にも。
- addした時点で、gitリポジトリの中に入れ込まれている?
- リセットしても.git/objectsの下からは消えない(ただ、この状態でほったらかしておくとどこからも参照されないからいずれgcされて死ぬ?)
$ git reset HEAD README Unstaged changes after reset: M README $ git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: README # no changes added to commit (use "git add" and/or "git commit -a") $ find .git/objects .git/objects/de/7e8558a365886d75f9c1ac6861693be19bdc53 .git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 .git/objects/54/3b9bebdc6bd5c4b22136034a95dd097a57d3dd .git/objects/b0/d99b34f1e2497a78619de4fde08b62f2d851f7 $ git cat-file -p de7e8558 このリポジトリはテスト用です
まとめ
以上の事から
- addした時、既にリポジトリにファイルは追加されている。また、インデックスの参照先も更新されている
addした後
- commitした時、インデックスがそのまま次のコミットのツリーオブジェクトになる。そのツリーオブジェクトを取りまとめるコミットオブジェクトを作成し、tree情報とparent情報を持たせる
- で、ブランチの参照先を更新してやる
Fluentdのプラグインを作成してみる(練習用)
前回までのあらすじ
Fluentdというログ収集ツールを使ってApacheのログを取得するまで - kk_Atakaの日記 で、confファイルのコメントアウトを外してとりあえず動くっていうところまではいけた。今度は簡単なプラグインを作ってみる。
ひたすら何かを吐き続けるプラグイン
Inputプラグインの場合
Fluent::Inputクラスを継承する。
class SimpleInput < Fluent::Input # 第一引数がプラグインの名前、<source> typeに指定される Fluent::Plugin.register_input("simple_in", self) def start @thread = Thread.new(&method(:run)) end def run loop do # emitメソッドの第一引数が <match **.**> の**に該当すればその形式で出力される # fluent.confでdebug.**はstdoutで出力すると定義されている Fluent::Engine.emit("debug.debug", Fluent::Engine.now, {"simple" => "debudebu"}) # fluent.confに<match simple.output> type simple_outを定義したので、以下のOutput形式で出力される Fluent::Engine.emit("simple.output", Fluent::Engine.now, {"simple" => "simout"}) sleep(1) end end end
上のソースには書かれていないけど、他にもメソッドがいくつか。(公式サイトより)
- configure メソッド
- スタート前に呼び出される
- confハッシュにパラメータを入れられる?
- エラーはFluent::ConfigErrorを投げる
- start メソッド
- スタート時に呼ばれる
- ここでスレッドを作ったりファイルをオープンしたり
- shutdown メソッド
- シャットダウン時に呼ばれる
- スレッドやファイルのクローズはここで。
- イベントをsubmitするためにはFluent::Engine.emit(tag, time, record)メソッドを使う
- tagはString、timeはUnixTime、recordはハッシュ。
Outputプラグインの場合
まず種類がいろいろ。
- Buffered output plugins Fluent::BufferedOutputクラスを継承
- Time sliced output plugins Fluent::TimeSlicedOutputクラスを継承/Buffered output pluginを継承したプラグイン?
- Non-buffered output plugins Fluent::Outputクラスを継承
今回はFluent::Outputを使った。
class SimpleOutput < Fluent::Output # 第一引数がプラグインの名前、<match> の typeに指定される Fluent::Plugin.register_output("simple_out", self) def emit(tag, es, chain) chain.next es.each do |time, record| # 出力内容 puts "simple_out: #{time} - #{record}" end end end
- configure, start, shutdown はInputプラグイン同様にある
- emit メソッドはイベントに到達した場合呼ばれる
- esはFluent::EventStreamオブジェクト(イベントが入ってる?)
- eachで回すとイベントを検索できる。
- chainはトランザクションメッセージのオブジェクト。
- 適切なポイントでchain.nextを呼ぶとエラーを吐いたときにrollbackしてくれる。
- esはFluent::EventStreamオブジェクト(イベントが入ってる?)
Configファイル
# Inputプラグイン指定 <source> type simple_in </source> # Fluent::Engine.emit("simple.output", Fluent::Engine.now, {"simple" => "simout"}) # simple.outputタグ指定した方はsimple_output(Outputプラグイン)出力にマッチする <match simple.output> type simple_out </match> # ## match tag=debug.** and dump to console # Fluent::Engine.emit("debug.debug", Fluent::Engine.now, {"simple" => "debudebu"}) # debug.debugタグ指定した方はstdout出力にマッチする <match debug.**> type stdout </match>
これを実行すると…。
$ bundle exec fluentd -c /home/kk_Ataka/fluentd/fluent.conf -p /home/kk_Ataka/fluentd/plugin/ 2012-08-17 22:19:41 +0900: starting fluentd-0.10.24 2012-08-17 22:19:41 +0900: reading config file path="/home/kk_Ataka/fluentd/fluent.conf" (略) 2012-08-17 22:19:41 +0900: following tail of /usr/local/apache2/logs/access_log 2012-08-17 22:19:41 +0900: following tail of /usr/local/apache2/logs/error_log 2012-08-17 22:19:41 +0900 debug.debug: {"simple":"debudebu"} simple_out: 1345209581 - {"simple"=>"simout"} 2012-08-17 22:19:42 +0900 debug.debug: {"simple":"debudebu"} simple_out: 1345209582 - {"simple"=>"simout"} 2012-08-17 22:19:43 +0900 debug.debug: {"simple":"debudebu"} simple_out: 1345209583 - {"simple"=>"simout"} 2012-08-17 22:19:44 +0900 debug.debug: {"simple":"debudebu"} simple_out: 1345209584 - {"simple"=>"simout"} 2012-08-17 22:19:45 +0900 debug.debug: {"simple":"debudebu"} simple_out: 1345209585 - {"simple"=>"simout"} 2012-08-17 22:19:46 +0900 debug.debug: {"simple":"debudebu"} simple_out: 1345209586 - {"simple"=>"simout"}
1秒刻みでプラグインに記述した内容が出力される。こっちが標準のstdout出力。
2012-08-17 22:19:46 +0900 debug.debug: {"simple":"debudebu"}
こっちが自分で記述したOutputプラグイン書式の出力。
simple_out: 1345209586 - {"simple"=>"simout"}
Sphinxの見出しについて学びなおし
前回までのあらすじ
- Sphinxでドキュメントを書くためreST記法に入門した - kk_Atakaの日記で見出しの理解が間違っている事をSphinx 初心者 さんに教えてもらった
- もう一度ドキュメントを見なおしてみる事に
見出し周辺を読み直し
セクションのヘッダは、セクションのタイトルを句読点などの記号の文字でアンダーラインを引くことで設定します。必要に応じてでオーバーラインも併用することができます。
使用していない種類のアンダーラインが出てくると、見出しのレベルが一段変わる、というルールになっています。
. These are a single line of text (one or more words) with adornment: an underline alone, or an underline and an overline together, in dashes "-----", equals "======", tildes "~~~~~~" or any of the non-alphanumeric characters = - ` : ' " ~ ^ _ * + # < > that you feel comfortable with.
つまり……
- 英数字以外の記号でアンダーラインを引くとセクションヘッダ
- アンダーラインとオーバーラインで囲むのも別の定義として判断される
- 己がしっくりくるものを選んでよい
- 初めて出てきた順に見出しレベルが割り当てられる
確認
Pythonドキュメント慣例にならってこういうソースを書くと、
################## 上下 # 部 ################## ここは上下 # で囲った部の文章。 下 # 部 ############## ここは下 # で囲った部の文章。 ******************* 上下 * 章 ******************* ここは上下 * で囲った章の文章。 下 * 章 ******************* ここは下 * で囲った章の文章。 =========================== 上下 = セクション =========================== ここは上下 = で囲ったセクションの文章。 下 = セクション =========================== ここは下 = で囲ったセクションの文章。 --------------------------- 上下 - サブセクション --------------------------- ここは上下 - で囲ったサブセクションの文章。 下 - サブセクション --------------------------- ここは下 - で囲ったサブセクションの文章。 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 上下 ^ サブサブセクション ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ここは上下 ^ で囲ったサブサブセクションの文章。 下 ^ サブサブセクション ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ここは下 ^ で囲ったサブサブセクションの文章。 """"""""""""""""""""""""""""""""" 上下 " パラグラフ """"""""""""""""""""""""""""""""" ここは上下 " で囲ったパラグラフの文章。 下 " パラグラフ """"""""""""""""""""""""""""""""" ここは下 " で囲ったパラグラフの文章。
htmlはこう生成される。
<h1>上下 # 部<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h1> <p>ここは上下 # で囲った部の文章。</p> <div class="section" id="id2"> <h2>下 # 部<a class="headerlink" href="#id2" title="Permalink to this headline">¶</a></h2> <p>ここは下 # で囲った部の文章。</p> <div class="section" id="id3"> <h3>上下 * 章<a class="headerlink" href="#id3" title="Permalink to this headline">¶</a></h3> <p>ここは上下 * で囲った章の文章。</p> <div class="section" id="id4"> <h4>下 * 章<a class="headerlink" href="#id4" title="Permalink to this headline">¶</a></h4> <p>ここは下 * で囲った章の文章。</p> <div class="section" id="id5"> <h5>上下 = セクション<a class="headerlink" href="#id5" title="Permalink to this headline">¶</a></h5> <p>ここは上下 = で囲ったセクションの文章。</p> <div class="section" id="id6"> <h6>下 = セクション<a class="headerlink" href="#id6" title="Permalink to this headline">¶</a></h6> <p>ここは下 = で囲ったセクションの文章。</p> <div class="section" id="id7"> <h7>上下 - サブセクション<a class="headerlink" href="#id7" title="Permalink to this headline">¶</a></h7> <p>ここは上下 - で囲ったサブセクションの文章。</p> <div class="section" id="id8"> <h8>下 - サブセクション<a class="headerlink" href="#id8" title="Permalink to this headline">¶</a></h8> <p>ここは下 - で囲ったサブセクションの文章。</p> <div class="section" id="id9"> <h9>上下 ^ サブサブセクション<a class="headerlink" href="#id9" title="Permalink to this headline">¶</a></h9> <p>ここは上下 ^ で囲ったサブサブセクションの文章。</p> <div class="section" id="id10"> <h10>下 ^ サブサブセクション<a class="headerlink" href="#id10" title="Permalink to this headline">¶</a></h10> <p>ここは下 ^ で囲ったサブサブセクションの文章。</p> <div class="section" id="id11"> <h11>上下 ” パラグラフ<a class="headerlink" href="#id11" title="Permalink to this headline">¶</a></h11> <p>ここは上下 ” で囲ったパラグラフの文章。</p> <div class="section" id="id12"> <h12>下 ” パラグラフ<a class="headerlink" href="#id12" title="Permalink to this headline">¶</a></h12> <p>ここは下 ” で囲ったパラグラフの文章。</p>
まあ、h12まであるページとか見たことないんだけど、新しいものを定義し続けるとどんどん深くなる。
ここでソースを以下のように編集。がっつりカットしつつ、適当に数個残し。あと<<<で新しいセクションを定義してみた。
# 部 ############## ここは下 # で囲った部の文章。 ******************* 上下 * 章 ******************* ここは上下 * で囲った章の文章。 下 - サブセクション --------------------------- ここは下 - で囲ったサブセクションの文章。 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 新しく作った <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<で新しくセクションを作ってみた。
htmlはこう生成される。
<h1>下 # 部<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h1> <p>ここは下 # で囲った部の文章。</p> <div class="section" id="id2"> <h2>上下 * 章<a class="headerlink" href="#id2" title="Permalink to this headline">¶</a></h2> <p>ここは上下 * で囲った章の文章。</p> <div class="section" id="id3"> <h3>下 - サブセクション<a class="headerlink" href="#id3" title="Permalink to this headline">¶</a></h3> <p>ここは下 - で囲ったサブセクションの文章。</p> <div class="section" id="id4"> <h4>新しく作った<a class="headerlink" href="#id4" title="Permalink to this headline">¶</a></h4> <p><<<<<で新しくセクションを作ってみた。</p>
うーんなるほど。
ちゃんとドキュメント読まず、他の記法と同じノリでこれはこの見出しって決めつけてしまっていた!