エンジニアですよ!

頑張れ俺くん、巨匠と呼ばれるその日まで

Laravel でログのフォーマット変えたり Monolog の Processor 追加したり

もう Laravel から Rails に移行する決意をしたもののめんどくさくて実際は放置、そうしてる間にもログをみることはあって不便だったりして仕方なくいじる。

やりたいのは

  • ユーザがログインしてたらエラーログに user id を extra に追加する
  • extra を表示する位置を先頭付近に持ってくる

の2つ。

公式の ↓ の Custom Monolog Configuration に設定の変更の仕方は載っている

laravel.com

設定を書くのは bootstrap/app.php で、Processor の設定はこのままこれで良さそう。

Monolog がわからないのでフォーマットの変更がよくわからなかったが、↓を参考にした。

blog.muya.co.ke

これだと getMonolog とかしているが、同じ場所でそのまま設定できるので別にファイルを作って...とかはやってない。

bootstrap/app.php で、Monolog のクラスを使うようにするのと、

<?php
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\LineFormatter;

return $app の直前に↓でやりたいことはできた。( extra に user_id 追加するのと、 extra を message の前に出す )

$app->configureMonologUsing(function ($monolog) use ($app) {
    $log_path = $app->storagePath().'/logs/laravel.log';
    $log_stream_handler = new StreamHandler($log_path);

    $log_format = "[%datetime%] %channel%.%level_name%: %extra% %message% %context%\n";
    $formatter = new LineFormatter($log_format);
    $log_stream_handler->setFormatter($formatter);
    $monolog->pushHandler($log_stream_handler);

    $monolog->pushProcessor(function ($record) {
        if (Auth::check()) {
            $user = Auth::user();
            $record['extra']['user_id'] = $user->id;
        }
        return $record;
    });
});

Vue.js の observe あたり雑に追う

(まとまりのなさがひどすぎてアレで放置してたらもう1.0.7になってますはい)

もう 1.0.4 になっとるやないけ

1.0.4 見ますはい。

データバインディングをどう実現しているのかが気になるのでその辺。

データバインディングといえば Observer ということで、 srsc/observer あたりを見てみようかと。

一年くらい前の記事だけど、 JavaScript フレームワークがデータバインディングを実現する4通りの手法 の中で、 Vue.js は「モデル書き換え方式」として紹介されている。

記事の中にもあるように、モデルを書き換えまくることで Vue.js はデータバインディングを実現してる。

おかげで特定のクラスのインスタンスを使わないといけないとかいうことはなく、意識せず使える。

ここから引用すると、 http://vuejs.org/guide/instance.html#Properties_and_Methods

var data = { a: 1 }
var vm = new Vue({
  data: data
})

vm.a === data.a // -> true

// setting the property also affects original data
vm.a = 2
data.a // -> 2

// ... and vice-versa
data.a = 3
vm.a // -> 3

console.log を仕込んでみると書き換えられている様子がわかる。

// インスタンスにセットする前
console.log(data) // -> { a: 1 }

// 後
console.log(data) // -> { a: [Getter/Setter] }

実際に取得できる値に変化はないけど、中身が書き換えられていることがわかる。 [Getter/Setter] という関数(?)になっちゃってる。


Observerhttps://github.com/vuejs/vue/blob/1.0.4/src/observer/index.js#L6L29 ここ。

コメントに、依存関係を収集したり(?)更新をディスパッチするために対象のオブジェクトのプロパティを geter/setter に変換するよ、って書いてある

  • Observer class that are attached to each observed
  • object. Once attached, the observer converts target
  • object's property keys into getter/setters that
  • collect dependencies and dispatches updates.

で、 Dep というオブジェクトが出てくるが、名前的にきっと依存関係を表すものかな。

_.define というので __ob__ というプロパティを対象のオブジェクトに生やして自分自身をそこに入れてる。

_.define は util で、 Object.defineProperty のラッパー

対象が配列なら何とかして(protoAugmentcopyAugment)配列用の便利関数的なものを生やしまくる。

そして walk で実際に convert していく様子

convertdefineReactive を呼び出す。

defineReactive によって、オブジェクトに getter/setter が定義されてる。

getter のほうは、値を返す前に depdepend をたくさん呼んでるが、これはなんだろう。

setter のほうは dep.notify してて、これは更新を伝えるためのものだろう。

Dep がわからんとわからんので src/observer/dep.jsを読む。

メンバ変数としてid, subsを持ってて、 target というクラス変数がある。

https://github.com/vuejs/vue/blob/1.0.4/src/observer/dep.js#L11L19

target には Watcher が入るみたいだがよくわからん。

さっきよく呼ばれてた depend は、targetaddDep を呼び出すもの。

うーん

watcher も見る。

https://github.com/vuejs/vue/blob/1.0.4/src/watcher.js

変更があったら何かを実行するのがこいつの役目。

addDep は自分自身の依存( newDeps, deps )に渡された dep を追加するのと、 depsub に自分自身を追加している

ちょっとこんがらがってきた

Observerインスタンスdep を持っていて、値を get するときに Watcherdepインスタンスdep を追加する

set の時には dep.notify を呼ぶことで、 depsubs を更新して回る。

get の際に addDep したタイミングで 自分のdep.subs にその時点での Dep.target (=watcher) が追加されてる。

nofity で呼ばれる update は、設定によって同期/非同期で値を更新する。

https://github.com/vuejs/vue/blob/1.0.4/src/watcher.js#L209

実際に更新するのはこっちの run メソッドBatcher から実行するためのインターフェースだと書いてある

https://github.com/vuejs/vue/blob/1.0.4/src/watcher.js#L237

ここで watcher 自身の value を更新してコールバックを呼び出している。

watcher を使っている場所を見てみると、 src/directive.js などにある。

https://github.com/vuejs/vue/blob/1.0.4/src/directive.js#L117L129

ここで第3引数が callback なので this._update が Watcher の値が更新されるときに呼ばれる callback ということになる。

this._updatedir.update を呼んでると。

https://github.com/vuejs/vue/blob/1.0.4/src/directive.js#L103L107

update を代入しているのはここ。 descriptor を調べる必要がある。

https://github.com/vuejs/vue/blob/1.0.4/src/directive.js#L79L83

descriptorコンストラクタで引数にとってるので Directive を初期化しているところを見に行く

https://github.com/vuejs/vue/blob/1.0.4/src/directive.js#L34

_bindDir で使われている

https://github.com/vuejs/vue/blob/1.0.4/src/instance/lifecycle.js#L109L113

_bindDir を使っているところはいくつかあるが、わかりやすそうなところでいくとここ

https://github.com/vuejs/vue/blob/1.0.4/src/compiler/compile.js#L395

で、 token.descriptor は何かなというと、雑に見ると恐らく下記

https://github.com/vuejs/vue/blob/1.0.4/src/compiler/compile.js#L360L365

publicDirectives[type] になる。

publicDirectives は何かというと

https://github.com/vuejs/vue/blob/1.0.4/src/compiler/compile.js#L2

var publicDirectives = require('../directives/public')

これなので、 directives/public を見てみる

https://github.com/vuejs/vue/tree/1.0.4/src/directives/public

各種ディレクティブのファイルが置いてある。

簡単そうだから text.js を見てみると、 update が定義されてる

https://github.com/vuejs/vue/blob/1.0.4/src/directives/public/text.js#L11L13

  update: function (value) {
    this.el[this.attr] = _.toString(value)
  }

まさに要素の中身を書き換えているようだ

まだ全体像は見えてないが、なんとなく値が更新された時に DOM にも反映される流れはつかめた。

__ob__ の役割とかよくわかってないな。また後で使いつつ読んでみる。

しかし大変だなー。 Object.observe が使えれば楽なのに

わたしとVue 今すぐダウンロード

小粒なうぇっぶあぷりを作ってて、 Vue.js を使いたいなと思ってる(使ってる)

小さいしドキュメントも充実しているので、ちょっとガイド読めば使えるのであんまり把握せずに使ってるけど、それはよくないよねということでコード読むところから始めようと思う

読むのはこれ。

https://github.com/vuejs/vue

現時点の Latest release な 1.0.1 を読む

v-cloak

最初は v-cloak.

理由は特になくなんとなく、簡単にわかりそうだから

http://vuejs.org/api/#v-cloak

要素に付けておくと Vue オブジェクトのコンパイルが終わると消える属性で、コンパイルが完了する前にテンプレートが表示されてしまうのを防ぐために CSS と組み合わせて使ったりするやつ。

ファイルを見てみるとそのものずばりな src/directives/public/cloak.js というのがあるのでそこに目を通す。

予想通りわかりやすそう。

compiled というフックに 'v-cloak' という属性を削除する関数を登録しているように見える。

こっから少し掘り下げてみる。

bind という名前で関数を export しているのはきっとそういう決まりかな。

src/directives/public 以下の他の js を見てみても、 bind という関数を export していそうに見える

bind が使われているところとかはもう少し後で見る。

cloak で src 以下を検索してみると該当するのはわずか。

cloak.js 自体と src/directives/public/index.js で cloak.js を require しているところ。

それとあと一箇所 src/directives.js で 'cloak' が使われてる。

https://github.com/vuejs/vue/blob/1.0.1/src/directive.js#L68L75

場所は Directive というオブジェクトの _bind 関数

属性が 'v-cloak' でないか vmコンパイル済みだったら属性を消すという感じの処理。

descriptor.attr ってのはなんなのかわからないが、'v-' なんとかの属性はどっかのタイミングで消すもののようだ。

その時に 'v-cloak' を先に消さないようにするための分岐っぽい。

そうすると vm ってのはちゃんと見たほうがよさそうだな〜

Directive から辿ってくと、 vmコンストラクタの第2引数なので、 new してるところを見る。

src/intance/lifecycle.js で new してる。

https://github.com/vuejs/vue/blob/1.0.1/src/instance/lifecycle.js#L111

_bindDir の中で new していて、第2引数は this

ここでの thisexports してる module 自体って理解でいいのかな

ということはこの lifecycle のオブジェクトなのか・・?

確かに、 _compile という関数の中で this._isCompiled という変数を設定しているようだ。

https://github.com/vuejs/vue/blob/1.0.1/src/instance/lifecycle.js#L68

さっき読んだところで this.vm._isCompiled というのがあったからなんとなくあってそう。

https://github.com/vuejs/vue/blob/1.0.1/src/directive.js#L70

今読んだ範囲だと vm を使っているところはあとひとつ、 $once というのがあった。

しかし $once を export しているのは src/api/events.js だなぁ。

vue/directive.js at 1.0.1 · vuejs/vue · GitHub

これは一体どういうことか。 lifecycle を require しているところを見れば多分わかりそう。

https://github.com/vuejs/vue/blob/1.0.1/src/vue.js#L85L86

src/vue.js で require している。

なるほど、 p というオブジェクトに extend していってるんだね。

確かに require('./api/events') もしている。

ということは↑の vmp オブジェクトで、 $once も持っているんで理解正しそう。

$once は予想通りな感じで、一回だけ関数が実行されるように登録された関数を実行したら登録を削除する処理を挟み込むようなもの。

さてじゃあ compiled という hook を呼んでるのはどこかな?と考えると、さっき compile っぽい関数あったよね。

はい、lifecycle.js

で、_isCompiled の直後にあるね、 callHook('compiled')

https://github.com/vuejs/vue/blob/1.0.1/src/instance/lifecycle.js#L69

これだよこれ。

callHook は src/instance/events.js で定義されている

https://github.com/vuejs/vue/blob/1.0.1/src/instance/events.js#L155L163

handlers があればひたすら呼び出していて、 handlersthis.$options に hook ごとに登録されてる。

でもここまで handlers というのは特に出てこなかったような気がする。

$emit のほうが大事かな。

フックで実行する関数の登録処理は $once あたりでやってるはず。

$once を見ると、実際登録してるのは $on っぽい。

https://github.com/vuejs/vue/blob/1.0.1/src/api/events.js#L10L34

$onthis._events に関数を push してる。

$emit をみてみると

https://github.com/vuejs/vue/blob/1.0.1/src/api/events.js#L89L105

_event に登録されているコールバックを apply で呼び出してる。

ということで、ここで最初に読んだところで登録された 'v-cloak' 属性を削除するコールバックが呼ばれて、コンパイルが完了すると 'v-cloak' 属性が消えてくれるということだ。

多分。

とりあえずこんなところ。

なんとなく構造がわかってきたしその辺もまとめつつまた読む。

いつもこうなんとなく読み始めちゃうけど、最初に全体像を把握したりとか、あとコメントに色々書いてあるんでコメント読んだりとかちゃんとしたほうがいいな〜と反省する

macでターミナルの起動がめちゃくちゃ遅くなってた

最近家のmacのターミナルの起動が超遅くてストレスを感じてた

きっとzshrcにいろいろ書きまくっているからだろうとそろそろ治すか・・と思ってたら、どうもターミナルの起動時とかタブを新しく開いた時によく見てみると遅いのは login だった。

login が遅いで調べると asl を消すとか出てくる。

Speed Up a Slow Terminal by Clearing Log Files | OSXDaily

asl は Apple System Log ということらしい。

login 時に last login を表示するときにここを検索してるんでここが肥大化すると遅くなるとか。

システムログなんかいらない!(わけない)ということで早速 /var/log/asl 以下のログを消して再起動してみるけど改善せず。

他に方法はないものかと探してると俺しか使わないmacだし quiet に login すれば良さそう。

.hushlogin を置いておくとできるようだが touch ~/.hushlogin しても変化なし

原因わからないのでこの辺は時間あるときにもうちょっと調べたいがとりあえずは iTerm の Profiles から起動時のコマンドをデフォルトの Login Shell (login -fp ) から Command に変更して、Commandに login -qfp <user> と入れる

これで速くなったのでとりあえずしばらくこれでしのぐ

ハロー "Hello, World" がおもしろい

まだ3章までしか読んでないけど、『ハロー "Hello, World"』がおもしろい

最近はLinux Kernelのコード読んだりしてみたいな〜と思って読んだりしてたんだけど、やっぱ膨大なのでとっつきにくい。

そこでこんな本を見かけたものだから、"OSと標準ライブラリのシゴトとしくみ" ってのに惹かれて買ってみた。

はじめに、の部分を軽く読んで「手を動かして、調べかたを知る」とか、資料に頼るんじゃなくて手を動かして調べることを重視した本なんだということが書いてあっていいねーと思う

やっぱり自分で動かしながら動きを追ってみないと頭に入ってこないなーと思ってたので色々な角度から解析してる本とかとても魅力的。

というわけで読んでみると、僕のような素人にも優しい感じ。

一章でアセンブラな解説もあるしVMの使い方とかも載ってる。

親切親切

二章から GDB を使ってがんばって題名の Hello, World を解析していく。

GDB はあんまり使ったことがなかったけどまぁ本の通りにやっていけばなんとなく動かせる

disable とか知らなかったけど便利だ

ひたすら追いかけるのはどこでどうやって hello world って文字列が出力されるのかということ

それを知るためにステップ実行してアセンブリ読んでコード読んで、後は確かめるために文字列を出力している部分のバイナリをnopに書き換えてみて出力されなくなることを確認したり。

おもしろい!!

IO はカーネルがやるからシステムコールカーネルに処理を頼むんだよなーとかそのくらいはわかってたつもりだし、CPUは動くときにレジスタ使ってどうこう、スタック使ってどうこうとかもなんとなーく知ってたけど、hello worldでそれが具体的にどう動いてるかと言われるとまぁよーわからんなーという程度の知識しかなかったんで、それを丹念に追っていくのは大変興味深い

システムコールに引数をどう渡すか、どう値を返すのか、エラーをどうセットするのか。

負の値を返せないのどうしてるのかとか、標準ライブラリの役割とか。

知らんことばかりでした

動かしながら学ぶとなんとなく納得感があっていい。

先が楽しみ

システムコールの定義

itpro.nikkeibp.co.jp

を読んでgrepしたり、http://lxr.free-electrons.com/ident?i= で検索してもなかなかシステムコールを定義してる箇所が見つからないなーと思ってたら、

SYSCALL_DEFINEx っていうマクロを使うようになってたのね。

SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
    struct fd f = fdget_pos(fd);
    ssize_t ret = -EBADF;

    if (f.file) {
        loff_t pos = file_pos_read(f.file);
        ret = vfs_read(f.file, buf, count, &pos);
        if (ret >= 0)
            file_pos_write(f.file, pos);
        fdput_pos(f);
    }
    return ret;
}

とか。

SYSCALL_DEFINEx 自体は include/linux/syscalls.h で

#define SYSCALL_DEFINE0(sname)                   \
    SYSCALL_METADATA(_##sname, 0);              \
    asmlinkage long sys_##sname(void)
    
..(略)..

#define SYSCALL_DEFINEx(x, sname, ...)              \
    SYSCALL_METADATA(sname, x, __VA_ARGS__)         \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...)                 \
    asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))   \
        __attribute__((alias(__stringify(SyS##name))));     \
    static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));  \
    asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));  \
    asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))   \
    {                               \
        long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__));  \
        __MAP(x,__SC_TEST,__VA_ARGS__);             \
        __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));   \
        return ret;                     \
    }                               \
    static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))

とかで定義されてる。

rust で数値からenumに変換する

rustのenumを定数を列挙するためだけに使いたいということもありますね?(ないですか?)

そういう時、数値からenumに変換したいということがありますね?(ないですか?)

rustのenumはこんなふうに定義します。 rustのenumはだいぶ高機能なのでいろんなことができますが、今回は定数の列挙に使いたいという想定ですね。

enum TrafficLight{
    Blue,
    Yellow,
    Red,
}

このように定義するとデフォルトで0から数値がふられるので enum から数値に 変換することはできます。

fn main() {
    println!("{:?}  = {}", TrafficLight::Blue, TrafficLight::Blue as i32);
    println!("{:?}  = {}", TrafficLight::Yellow, TrafficLight::Yellow as i32);
    println!("{:?}  = {}", TrafficLight::Red, TrafficLight::Red as i32);
}

結果

$ cargo run
Blue    = 0
Yellow  = 1
Red     = 2

こうなります。

逆はできません。

$ cargo build
src/main.rs:12:32: 12:49 error: non-scalar cast: `i32` as `TrafficLight`
src/main.rs:12     let light : TrafficLight = 0 as TrafficLight;
                                              ^~~~~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `light`.

To learn more, run the command again with --verbose.

こうなります。

調べてみると以下がでてきますね。

stackoverflow.com

書いてある通りに std::num::FromPrimitive は削除されてしまいましたが、今は http://doc.rust-lang.org/num/num/index.html に同様な機能を持つものが入っています。

crateに頼ることになるのは遺憾ですが公式が提供してる(?)ものなのでまぁいいとしましょう。

これを使って FromPrimitive という trait を実装すると

from_i64(n: i64)
from_u64(n: u64)
from_isize(n: isize)
from_i8(n: i8)
from_i16(n: i16)
from_i32(n: i32)
from_usize(n: usize)
from_u8(n: u8)
from_u16(n: u16)
from_u32(n: u32)
from_f32(n: f32)
from_f64(n: f64)

これらが使えるようになるので、基本の数値型ならどれからでも変換できるようになります。

実装する必要があるのは、 from_i64from_u64 の2つです。

以下使い方

Cargo.toml に依存を追加しましょう

[dependencies]
num = "*"

で実装してきます

extern crate num;
use num::traits::FromPrimitive;

impl FromPrimitive for TrafficLight {
    fn from_i64(n: i64) -> Option<TrafficLight> {
        match n {
            0 => Some(TrafficLight::Blue),
            1 => Some(TrafficLight::Yellow),
            2 => Some(TrafficLight::Red),
            _ => None,
        }
    }
    fn from_u64(n: u64) -> Option<TrafficLight> {
        match n {
            0 => Some(TrafficLight::Blue),
            1 => Some(TrafficLight::Yellow),
            2 => Some(TrafficLight::Red),
            _ => None,
        }
    }
}

こうです。

このmatchあたりがめんどくさいのでなんとかしたいですね。いい方法があるといいんですが。

ここに数値を書かないといけないとなると網羅してるかもよくわからないし変更や追加に弱いしこれはなんとかしたいです。

(これのいい方法が知りたくてこんな記事をだらだら書いてると言っても過言ではありません。誰か教えてください。)

    let blue = TrafficLight::from_i64(0 as i64).unwrap();
    let yellow = TrafficLight::from_u8(1 as u8).unwrap();
    let red = TrafficLight::from_usize(2 as usize).unwrap();
    println!("{:?}", blue);
    println!("{:?}", yellow);
    println!("{:?}", red);

結果

$ cargo run
Blue
Yellow
Red

できましたね