2014年9月17日水曜日

awkの'{print $n}'の$nをいくつにすればいいのかすぐ見つけたい

アクセスログからawk '{print $1}' でIPだけ集計したりしますが、ほかの項目を集計するときは数字をいくつにすればいいのかわからない。

$10にしてみるー>違うなー>アクセスログみるー>調整、を繰り返す。

面倒くさい!となったので番号を振るようにしました。
head -1 access_log | awk '{for(i=1;i<NF;i++){ printf "%d:%s\n",i,$i;} }'

これを手打ちorコピペorエイリアスするのも面倒くさいので、もっと簡単な方法ないだろうか。

2014年9月16日火曜日

IO::Socket::SSLのデフォルトがipv6だった

IO::Socket::SSLは、IO::Socket::INET6がインストールされてるとそれを優先してしまう。

IO::Socket::SSLはexporterでoption指定するようで、
use IO::Socket::SSL qw/inet4/
とするとipv4を強制できる。

またqw/debug3/とするとデバッグトレースが表示される。

2014年9月15日月曜日

文字列連結でメソッド名を組み立てて実行する、を一行で。(perl)

リファレンスにしてデリファレンスする。わけわからないので、滅多に使わない。
  $self->${ \"method_${type}" }

2014年9月14日日曜日

コードリファレンスから名前取得

#!/usr/bin/env perl
use strict;
use warnings;
use B;


sub print_hoge {
    print "hoge\n";
};

my $coderef = \&print_hoge;

warn B::svref_2object($coderef)->GV->NAME; #print_hoge

2014年9月13日土曜日

どのmy.cnfが読まれてるか調べる

前回のISUCONでmy.cnfがどこにあるのか分からないチームが結構いて、
その後、yoku0825さんが投稿してた内容です。
$ strace -ff -e open   /usr/local/mysql/bin/mysqld_multi  start 55,56 2>&1 | grep my\.cnf
[pid 23345] open("/etc/my.cnf", O_RDONLY|O_LARGEFILE) = 3
[pid 23347] open("/etc/my.cnf", O_RDONLY|O_LARGEFILE) = 3
[pid 23344] open("/etc/my.cnf", O_RDONLY|O_LARGEFILE) = 3
mysql --helpだと
Default options are read from the following files in the given order:
の箇所にデフォで読み込まれる順番が書いてあるんですが、デフォのときの話だし、straceでみるのが楽ですね。

configureの設定は昨日の記事でどうぞ。

2014年9月12日金曜日

mysqlのconfigureオプションを調べる

$ strings /usr/local/mysql/bin/mysqlbug | grep configure
# This is set by configure
CONFIGURE_LINE="./configure '--prefix=/usr/local/mysql'.....

2014年9月11日木曜日

apacheやnginxの設定を環境毎に手書きしない

~/myapp/etc/development/nginx.conf
~/myapp/etc/production/nginx.conf
上記のように開発環境と本番環境の2つを別々に管理していると、開発環境でテストしてもテストできたのはdevelopmentのほうだけで、 実際に使われるproductionのほうはテストされてません。

ぶっつけ本番と変わらないわけです。

なので、テンプレート化して生成するようにしましょう。やり方は簡単です。
環境ごとにバラバラに膨れ上がった設定ファイルでも本番環境のものが正なので、それを元にテンプレートファイルを作成していきます。本番の設定ファイルと同じものが生成されるかdiffを見ながら作業すればいいので半日で終わります。
テンプレートに渡す環境ごとのパラメータ(ホスト名など)はアプリ側で使用しているものがあると思いますので、それを使えばいいです。

テンプレートエンジンはなんでもいいのですが、どこでも同じものが使いたいので、Text::MicroTemplateを使っています。
nginx.conf
    server {
        listen       80;
        server_name <?= $_[0]->{PROJECT_HOST} ?>; 
        ....
    }

make.pl
#!/usr/bin/env perl

use File::Slurp qw/ write_file /;
use Text::MicroTemplate qw/:all/;
use Text::MicroTemplate::File;

my $mtf = Text::MicroTemplate::File->new(
    include_path => [ 'tmpl' ],
);

for my $env (qw/ development production /) {
    my $C = do "../config/${env}.pl";
    die $@ if $@;
    warn $C->{PROJECT_HOST};
    my $filled_template =  $mtf->render_file('nginx.conf', $C);
    write_file( "${env}/nginx.conf", {binmode => ':utf8'},$filled_template );
}
make.plを実行すると各種ファイルが更新されます。
ちなみにこの手の自動生成系はテストの実行時に毎回実行するようにしてあります。

2014年9月10日水曜日

memcachedのdeleteの第2引数が削除されたバージョンを調べる

某サービスが延々と警告を吐いてるので確認すると、
Cache::Memcached::Fastが「non-zero delete expiration time is ignored」を出力していた。

ある時点まではdeleteの際にdelay時間を設定できていたが、今は無くなっている。

どのバージョンから?

githubのmemcachedのプロジェクトを見ると、protocol.txtがあり、ここに記述があった。
    $ git log -p 5da8dbab2a815c00617ab60b641391ada8d96f40 protocol.txt
    $ git name-rev 5da8dbab2a815c00617ab60b641391ada8d96f40
    > 5da8dbab2a815c00617ab60b641391ada8d96f40 tags/1.3.2~164
1.3.2からでした。

使ってるmemcachedのバージョンを確認する

    $ memcached -h | head -1

余談

Sledge::Session::Memcachedの_delete_meがこんな実装になってたら注意。
sub _delete_me {
    my $self = shift;
    $self->{_dbh}->delete($self->{_sid}, $self->{_data});  #秒数入れる第2引数にハッシュリファレンスいれてる
}
プロトコルが何回か変わったのかもしれませんが、$self->session->expireがまったく効いてませんでした。

2014年9月9日火曜日

Tengなどのsingleメソッドで気をつけること

意図しないレコードを取得する危険性があるのでバリデーションしましょうという話。

Tengの場合

Tengの場合、デフォルトではSQL::Makerを使用しますが、
以下の$whereが空ハッシュ{} の場合
$db->single( member => $where );
DBIx::QueryLogで確認すると、
SELECT (略) FROM `member` LIMIT 1
となります。 Amon2を使ってる場合、MyApp::DBにsingleメソッドを作ってそこでバリデーションしています。

MongoDB

MongoDBのfind_oneメソッドもこれと似た挙動をするはずなので注意。
というか元々は1年ほど前にMongoDBでビックリして以来、他でも気を付けていたらTengで見つけたのでした。

一つじゃなくてユニークが欲しい

自分がsingleを使うときは複数あるものから1件だけ欲しいのではなく、ユニークなレコードを取得したいときなので、 singleじゃない、ボッチメソッドがあるといいな

2014年9月8日月曜日

サーバー側のDBスキーマからCoreDataモデルを生成する

前回のJSONからCoreDataモデル生成に引き続き、今回はSQLiteからCoreDataモデル生成です。
Sqlite2CoreDataを使用すると、簡単にSQLiteのDBファイルからCoreDataモデルを生成できます。

Sqlite2CoreData

ググっても317件しかないマイナーツールです。
本邦初公開。

使い方

githubに書いてある通りですが、distribution.zipファイルを解凍して
./sqlite2coredata mydb_file
mv   ~/output/myapp.xcdatamodeld/myapp.xcdatamodel/contents   ~/hoge/myapp.xcdatamodeld/myapp.xcdatamodel/contents

注意

cloneしたディレクトリ外に実行ファイルを移動して使うとmomの生成に失敗します(特に困りませんが)。
また現状blobを上手く型変換してくれないようです。

MySQLから生成

perlのSQL::TranslatorでMySQLのスキーマからSQLiteのスキーマに変換して、Sqlite2CoreDataを使います。 SQL::Translatorをインストールするとsqltスクリプトが付属しているので、
$  sqlt  -f  MySQL  -t  SQLite  ~/test.sql   >  test_sqlite.sql
しかし括弧でサイズ指定などしている箇所が残っているので、ワンライナーで削除しました。

使いどころ

サーバーと同じスキーマが必要なことはまずないですが、まっさらな状態からXcodeのGUIを触るよりはマシ、、

2014年9月7日日曜日

JSONからCoreData(xcdatamodeld)を生成する


JSON Accelerator

MacのデスクトップアプリであるJSON Acceleratorを使用します。
起動後、右上の地球?マークをクリックすると、URLを入力する欄があるので、
そこにJSONを返すAPIを指定します。(ファイルやJSON手入力でも可)


データを取得すると整形されたJSONが表示されます。
「ファイルを作成する」ボタンを押し、出力言語の選択は「Core Data (Objective-C)」にします。

xcdatamodeldと各ソース(*.m,*h)が出力されますが、ソースはmogeneratorなど別のツールを使いたいので、xcdatamodeledだけ頂いて完了です。

JSONに配列が含まれていれば1対多のリレーションにしてくれます。

使いどころ

自分のコントロール配下にない他社のAPIをアプリから利用したい場合

2014年9月6日土曜日

Amon2+Tengでviewから更新クエリを発行させない

forで回してるときに間違ってdeleteでもしようものなら恐怖、、、なので、 MyApp::Webにrenderメソッドを定義(オーバーライド)して、そこでメソッドを無効化してます。local便利!

sub render {
    my ($c,$filename,$vars) = @_;
    ....
    no warnings 'redefine';
    local *Teng::Row::update = sub { die 'Teng::Row::update not allow in view' };
    local *Teng::Row::delete = sub { die 'Teng::Row::delete not allow in view' };
    ....
    $c->SUPER::render(...);
}

2014年9月5日金曜日

mysqlのprocesslistを毎秒表示する

コマンドの定期実行はwatchコマンドが定番だと思いますが、mysqladminに付属しているのでメモ。
mysqladmin -i 1 processlist
秒数の指定は省略不可

2014年9月4日木曜日

サービスにfork機能を付けたいときのテーブル設計

動機

数年前に電子書籍サービスで二次創作、三次創作、、、とforkしていく機能を作る必要がありました。 親子関係を記録するテーブルのカラムに親のbook_idを保持していれば、自分の親と子供は簡単に取れますが、一族を全部取得したいという要望も出てくるかもしれない。

その場合、サブクエリで再帰的に〜は明らかに悪手。
で、ディレクトリ構造と一緒で、パスで表現すればいいな、と考えました。

pathカラムを追加

pathカラムを追加して、そこにbook_idを/で連結した値を格納。
"/1386/1521/1777"の場合、book_idが1777の本についてのfork情報で、1521が親で、さらにその親が1386。

メリット
パス形式にすると、自分の子孫レコードをパス同士の前方一致で見つけることができる。
index付きでlike検索が使えます。
注意事項
パスを格納するカラムの最大文字列長を確認しておく(大体杞憂に終わると思いますが)

2014年9月3日水曜日

.bashrcをちゃんと管理したい

今まで**envのパスやエイリアスを追記していく度に、少しずつ汚くなっていく.bashrcにゲンナリしていて、.bashrcを育てようという気は全くありませんでした。
そのため.bashrcはfunctionも入れて100行もない。

かと言って、このままではダメだろー、、、こう、、、プログラマとして、、、。

そんなわけで、重い腰を上げてとりあえず.bashrcを分割することにしました。
emacsのinit-loaderと同じように、.bash.dというディレクトリの下に00_init.sh, 10_hoge.sh, .... と分割したファイルを配置して、
        if [ -d "${HOME}/.bash.d" ] ; then
            for f in "${HOME}"/.bash.d/*.sh ; do
                . "$f" && echo load "$f"
            done
            unset f
        fi
で読み込みます。(このやり方の元ネタがあったけど忘れた)

echoはなくてもいいのですが、このほうが新しいshellを立ち上げたときに分かりやすかったのでこのままにしてあります。

2014年9月2日火曜日

Perlの継承関係を簡単にグラフ化したい

継承関係のグラフ化はプロジェクトの全体像を知るために何度か使ったことはあるのですがうまくいかないケースもあり、敬遠していました。

うまくいかない原因を思い出してみると、1つは継承関係を知るためには実際にコードを動かす必要があるけれど、手元に必要なライブラリがない、ミドルウェアがないため実行できないケース。もう1つはパッケージの数が多くグラフ化の処理が重すぎる、の2点でした。

前者を解決するためには、実際に動かさないで継承関係を知る必要があるため、、、、コードの静的解析、PPIで解決しました。
後者は、グラフ化する対象を絞ることにしました。

要件

指定したディレクトリ以下にあるモジュール間の継承関係をグラフ化する。
(例:MyProj::Authorizer::**以下にある認証フローにしか興味がない)

コード

コードはgistを参照。

コード解析にはFile::PackageIndexerを使用していて、これはPPIを使ってISAやメソッドを収集してきます。1箇所テストが失敗しますが気にしなくていいです。直すかnotestで入れてください。
これで子パッケージ名と親パッケージ名の組のリストを作っていきます。

次にGraph::Easyのadd_edgeメソッドに先ほど作ったパッケージリストを設定します。
$graph->add_edge(A,B)
$graph->add_edge(B,C)
で A => B => C のような関係をグラフ化してくれます。

黄色は指定ディレクトリ内で見つからなかったパッケージのノードを表し、赤色はそれ以上親がいないノードを表しています。

以上ー。
他に良いものがあれば教えてください。

2014年8月30日土曜日

YAPC::Asiaのご飯とデザートがすごかった

感想そこ?って感じですがw
料理がなくなる前にがっついてたら、次々補充されて食いきれず。
む、無限料理、、、。

デザートも想像してたよりたくさん種類がきてテンションあがった。
バケツプリンなんて久しぶりにリアルでみた!



未開の台地を切り開け!ど真ん中をいくんだ!
などと初対面の若者(@_Yasuun_)に絡んでました。

 あと、バケツプリンもてっぺんから掘ろうぜ!って言ってたけど、無難な感じになりました。

video
常に帽子の@outerinside


2014年6月17日火曜日

GNU Screenのwindowリストを配列操作するモジュールを書いた

動機

windowを任意の場所に追加できないことが不満だった。歯抜けのwindow番号があるときにwindowを追加すると歯抜けの中で一番若い番号に作成される。作成後に移動できるがコマンドが覚えられないし、手間がかかる。また歯抜け状態を一括で無くしたいとも思っていた。

仕様

windowリストを配列のように操作できること。歯抜けの部分はnullが格納されている要素と考える。メソッドはpush,insert,compactの3種類。
insertは引数を伴わない場合は現在選択しているwindowの番号+1がデフォルト値になる。

実装方法

screen -Q [command] の出力をパースすることで歯抜けの状態や、現在選択しているwindowを知ることができる。この情報を元にwindowリストを操作する。
言語はPerl。コアモジュールのみ使用している。

使い方

インストール
cpanm Term::GnuScreen::WindowArrayLike;
もしくはMinillaを使用しているのでgithubからリポジトリを取得してminil install。 Qオプションがない場合、新しいバージョンのscreenをインストールしてください。
screenから呼び出し

    # .screenrc
    # push is [C-t l p]
    escape ^Tt
    bind  l command -c window_array_like
    bind  -c window_array_like  p exec perl -e 'use Term::GnuScreen::WindowArrayLike; Term::GnuScreen::WindowArrayLike->new->push'
.screenrcを設定して任意のキーに割り当てて使用する。上記はC-t + l + p でpushメソッドが実行される。
このように2キー(lとp)を登録したい場合は、-cで任意のクラス名を割り当てて使用する。

TODO

insertに任意の引数を渡せるようにする.screenrc設定がわからない
screenコマンドが遅い


2014年6月10日火曜日

cpandocをキャッシュするモジュールを書いた

動機

 cpandocはモジュールをインストールしなくても素早くドキュメントや実装が見れて便利だし、cpandoc -c でchangesが見られるのも素晴らしい。
 しかしネット経由なので3秒ほどかかる。1回だけならいいが数分の間に何回も見ることがあるので、そうなると毎回3秒待たされるのは辛い。

仕様

 ローカルマシンにcpandocがfetchしてきた情報をキャッシュします。キャッシュ期限は24時間です。それより早く消したいことも稀にあると思いますが、その場合はキャッシュファイルを削除してください。

使い方

 使い方は、SYNOPSISに書いてある通りですが、

$ cpanm Pod::Cpandoc::Cache
$ ccpandoc Acme::No
$ ccpandoc -m Acme::No
$ ccpandoc -c Acme::No

 # support Pod::Perldoc::Cache
$ ccpandoc -MPod::Perldoc::Cache -w parser=Pod::Text::Color::Delight Acme::No

コマンド名由来

ccpandocという名にした理由は、出来るだけ短い名前が良い、かつmcpandocという名が存在するので合わせた形です。aliasを設定すればいいといえ、各マシンで設定するのは面倒くさいので出来るだけ短いほうが良かった。

追記
metacpanへのリンク