perl で複数のプロセスからログを吐くときは :unix layer で開いてもいい
File::RotateLogs
が大変便利でよく使っているのだが、これはファイルへ書き込むときに print
を呼んでいる。
一方
によると長いログを吐くときは syswrite
にしないと混ざるとある。
よって File::RotateLogs も実は混ざることがあるのかなと思い、複数プロセスから長いログを吐きまくってみたが一向に混ざらなかった。
いろいろ調べた結果、open layer に最も低級な layer である :unix
を指定すれば
print
時も 1 つの write(2) になるようだった。
> cat test.pl
open my $fh, ">:unix", "test.txt";
print $fh "a" x (1024 * 100);
> strace perl test.pl 2>&1 | grep write
write(3, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 102400) = 102400
そして、File::RotateLogs はしっかりと :utf8:unix
で open していた。流石である。
まとめ
perl で複数のプロセスからログを吐くときは syswrite, もしくは open layer を :unix にすべき。
余談
標準 open layer は大抵の場合 :unix:perlio
のため、:perlio
を外すという意味で
open my $fh, ">:pop", "file";
としてもよさそうではある。
メモリ使用量をログに吐く
cron で 5分毎に動かしているプログラムでメモリ使用量が気になるものがあったため、 下記のようにしてメモリ使用量をログに吐いたところ、いろいろ捗った。
use Log::Minimal; sub rss { my $rss = `ps -p $$ -o rss=` || 0; $rss =~ s/\s+//gsm; $rss; # KB } infof "memory usage: %dMB", rss() / 1024; __END__ 2015-01-31T11:24:58 [INFO] memory usage: 4MB at rss.pl line 9
perl を build するとき man page を作らない
-Dman1dir=none -Dman3dir=none
をつければいいらしい。
$ ./Configure -Dprefix=$HOME/hoge -des -Dman1dir=none -Dman3dir=none $ make -j`nproc` install
plenv の場合も
$ plenv install 5.20.1 -j`nproc` -Dman1dir=none -Dman3dir=none
でいい。
perldoc があるので、man page はほとんど無意味である。
remote サーバで pbcopy for iTerm2
pbcopy は MacOSX 用の標準入力をクリップボードにコピーしてくれる便利ツールだが、 local でしか利用できない。
しかしながら実際のところ、OSC52 エスケープシーケンスを使えば remote サーバからも クリップボードにアクセスできる。下記 url に詳しく書いてある。
- http://doda.b.sourceforge.jp/2011/12/15/tmux-set-clipboard/
- http://qiita.com/kefir_/items/1f635fe66b778932e278
- http://qiita.com/kefir_/items/515ed5264fce40dec522
ということで iTerm2 前提の remote サーバ用 pbcopy を用意してみた。
注
以下、おそらく不安定な nightly の iTerm2 を使い、 さらにセキュリティ上の問題をはらむ OSC52 を使う。
インストール
まず OSC52 で読み込めるデータサイズ制限をなくした iTerm2 をインストールする (そうしないと base64 encode 後の1024 byte しかコピーできず役に立たない)。 http://iterm2.com/downloads/nightly から nightly を ダウンロードし、解凍してでてきた iTerm.app を /Applications におけばいい (もっといいインストール方法がある気がする)。
また iTerm2 の Preference で "Allow clipboard access to terminal apps" にチェックをいれておく。
あとは remote サーバで github から pbcopy をダウンロードすればいい。
[remote] $ wget https://raw.githubusercontent.com/shoichikaji/remote-pbcopy-iterm2/master/pbcopy
[remote] $ chmod +x pbcopy
[remote] $ mv pbcopy /path/to/bin/
使い方
普通の pbcopy と同じように使える。
[remote] $ echo "copy data to clipboard from remote!" | pbcopy
[local] $ pbpaste
copy data to clipboard from remote!
See also
iTerm2 の "OSC52 で読み込めるデータサイズ制限" に関する issue:
TeraTerm 版 pbcopy
cpan module を symlink で管理できるか
昨日 吉祥寺 pm に参加し、songmu さん、charsbar さんと miyagawa さんの開発している carmel についてお話しすることができた。(主催していただいたmagnoliaさん、ありがとうございました!)
その中で、PERL5LIB にたくさんの path を突っ込むのではなく、symlink で一つのところにまとめてその path のみを設定するのはどうか、という話になった。
これは以前から話題にはなるらしいが、charsbar さんいわく 「ある module の属する distribution が変わったときが大変」とのこと。確かに。
しかし、一度やってみないとその良さ、悪さが自分には理解できないので作ってみた。
これは symlinklib ディレクトリ以下に symlink を作りまくりその path を PERL5LIB に設定し exec できるやつである。
使い方:
> carmel install Plack@1.0030 > cat "requires 'Plack', '== 1.0030';" > cpanfile > what-happens exec perl -MPlack -e 'printf "Plack %s in %s\n", Plack->VERSION, $INC{"Plack.pm"}' Plack 1.0030 in /Users/skaji/symlinklib/lib/Plack.pm > what-happens exec env | grep PERL5LIB PERL5LIB=/Users/skaji/symlinklib/lib
そんなに悪くない気がする。(charsbar さんに指摘していただいた問題はちゃんと artifact を選べれば大丈夫か?)
Carmel 使ってみる
https://github.com/miyagawa/Carmel を使ってみる!
注:miyagawa さんに教えていただき cpanm インストール方法、例ともに修正しました https://gist.github.com/shoichikaji/5a951ab796ed0e596c47/revisions
まず copy-build-artifacts ブランチの cpanm をインストール
$ cpanm File::Copy::Recursive # 依存してるのではじめに入れておく $ cpanm git://github.com/miyagawa/cpanminus.git@copy-build-artifacts
Carmel をインストール
$ cpanm git://github.com/miyagawa/Carmel.git
Plack のバージョン1.0033, 1.0030を切り替えてみる。
$ carmel install Plack@1.0033 $ carmel install Plack@1.0030 $ ls -F ~/.cpanm/builds/ | grep Plack Plack-1.0030/ Plack-1.0033/ $ echo "requires 'Plack', '== 1.0033';" > cpanfile $ carmel exec perl -MPlack -e 'printf "Plack %s in %s\n", Plack->VERSION, $INC{"Plack.pm"}' Plack 1.0033 in /Users/skaji/.cpanm/builds/Plack-1.0033/blib/lib/Plack.pm $ echo "requires 'Plack', '== 1.0030';" > cpanfile $ carmel exec perl -MPlack -e 'printf "Plack %s in %s\n", Plack->VERSION, $INC{"Plack.pm"}' Plack 1.0030 in /Users/skaji/.cpanm/builds/Plack-1.0030/blib/lib/Plack.pm
carmel exec は PERL5LIB にPlackが依存する ~/.cpanm/builds/*/blib/{arch,lib} を加えることでこれを実現している:
$ echo "requires 'Plack', '== 1.0030';" > cpanfile $ carmel exec env | grep PERL5LIB PERL5LIB=/Users/skaji/.cpanm/builds/Plack-1.0030/blib/arch:/Users/skaji/.cpanm/builds/Plack-1.0030/blib/lib:/Users/skaji/.cpanm/builds/Apache-LogFormat-Compiler-0.32/blib/arch:/Users/skaji/.cpanm/builds/Apache-LogFormat-Compiler-0.32/blib/lib:/Users/skaji/.cpanm/builds/Devel-StackTrace-2.00/blib/arch:/Users/skaji/.cpanm/builds/Devel-StackTrace-2.00/blib/lib ...
Note
- bundler の挙動に近くなった。
- 同一モジュールの異なるバージョンを保持できて、簡単にスイッチできるようになった。すばらしい!
- ~/.cpanm/builds を共有するのでインストールの時間が節約されそう。
- cpanfile.snapshot を使えば依存も含めてバージョン指定できる。
- 環境変数 PATH, PERL5LIB が相当長くなりそう。cf: http://d.hatena.ne.jp/gfx/20130118/1358476166
App::FatPacker::Simple
App::FatPacker::Simple というのを書いた。
これはモジュールの依存関係は 使う人が理解しているという前提 で fatpack するところだけいい感じでやってくるやつである。
INSTALL
> cpanm git://github.com/shoichikaji/App-FatPacker-Simple.git
App::FatPacker との関係
App::FatPacker は、あるスクリプトを その依存モジュールをすべて含めた形にまとめてくれるツールである。
利点としては、
がある。実際 cpanminus は fatpack された形で配布されていて その利点を多くの人が享受しているように思う。
一方で一度やってみればわかるが App::FatPacker は、はまりどころにあふれていてなかなか使いこなせない。
App::FatPacker は大きくわけて
をやっている。 この 1. が特にはまりどころ満載で、 2. については単に融通が利かないという感じである。
App::FatPacker::Simple は 1. については使う人がしっかり理解しているという前提で、2. だけの面倒を見る。
個人的に 1. を機械的に解決するのは無理だと思っている。
使い方
(以下の例は https://github.com/shoichikaji/fatpack-example にある)
例えば hello.pl
があり、それは lib/Hello.pm, lib/Hello/CLI.pm
を元にしているとしよう。
また外部依存モジュールは cpanfile に書かれているとする。
> find .
.
./cpanfile
./hello.pl
./lib
./lib/Hello
./lib/Hello/CLI.pm
./lib/Hello.pm
> cat cpanfile
requires "Sub::Retry";
requires "HTTP::Tiny";
App::FatPacker::Simple およびそのフロントエンド fatpack-simple
は
カレントディレクトリの
lib, local, fatlib, extlib ディレクトリにあるモジュールを
perl-strip して fatpacked スクリプトを作るだけである。
よってまず 依存モジュールを local, extlib などにインストールする。
> carton install
Installing modules using /Users/skaji/cpanfile
Successfully installed CPAN-Meta-2.143240 (upgraded from 2.140640)
Successfully installed Module-Build-0.4210 (upgraded from 0.4205)
Successfully installed Sub-Retry-0.06
3 distributions installed
# Sub::Retry は parent モジュールに依存すると **あなたが理解してる前提**
# HTTP::Tiny も fatpack すべきだと **あなたが理解してる前提**
> cpanm -nq --reinstall -lextlib parent HTTP::Tiny
Successfully reinstalled parent-0.228
Successfully installed HTTP-Tiny-0.053 (upgraded from 0.049)
2 distributions installed
その後、fatpack-simple を実行すればいい。ただしこのままだと build 時しか入らない Module::Build なども入るので それは exclude する。
> fatpack-simple --exclude Module::Build,CPAN::Meta hello.pl
-> perl-strip lib/perl5/parent.pm
-> perl-strip lib/perl5/HTTP/Tiny.pm
-> perl-strip Hello.pm
-> perl-strip Hello/CLI.pm
-> exclude CPAN/Meta.pm
...
-> exclude Module/Build.pm
...
-> perl-strip Sub/Retry.pm
すると hello.fatpack.pl ができる。
ちなみに以上の作業を Daikufile にまとめておくと便利。
> daiku fatpack
# get hello.fatpack.pl
その他
こうしてできた hello.fatpack.pl
を実際実行させたい perl (例えば 5.8.8 とか)
でテストすべき。
fatpack 自体を perl 5.8.8 などでやるという考えもあるが、 個人的に最新の perl で fatpack を作り、5.8.8 でテストの方がいいと思っている。
Enjoy fatpack!