生涯未熟

生涯未熟

プログラミングをちょこちょこと。

sirupsen/logrusのユーザー名変更問題について

皆さんはGoでプログラミングする際にloggerは何を使ってるでしょうか?
様々なloggerがありますが、その中でも sirupsen/logrus を使っている方は多いと思います。

ただ、このlogrusに大きな問題が起こりました。
それはsirupsen氏がGithubのユーザー名をSirupsenからsirupsenにリネームしたことが発端でした。

一体何が起こったのか?

「ユーザー名のリネームくらい良いじゃない」と思われるかもしれませんが、これがlogrusを使ってる側からするとなかなか面倒な話になります。

例えば、glideやdepなどのパッケージマネージャを使っている場合には、一度 Sirupsen/logrus で保存されてしまったキャッシュをわざわざ削除し、 surupsen/logrus で新たにvendorにインストールし直さなれけばならないのです。

また、使用しているパッケージでの依存パッケージが Sirupsen/logrus となっている場合、これまたややこしい話になるのでglideでは以下のように対処したりします。

- package: github.com/sirupsen/logrus
  version: master
- package: github.com/Sirupsen/logrus
  repo: https://github.com/sirupsen/logrus.git
  version: master

Sirupsen/logrus でのVCSエンドポイントを sirupsen/logrus としてあげる形ですね。

こういった問題が起こったため、glideやdepなどのパッケージマネージャ・logrusで「Sirupsenがsirupsenになったせいでなんか動かなくなった!」的なIssueが乱立しました。

以下はその一部。

github.com

github.com

github.com

というわけで

いちユーザーとしては「何故ユーザー名変えたし・・・」という感想です。
先ほどの"Rename back to Sirupsen/logrus"のIssueでSirupsen氏が何故ユーザー名を変更したのか?について説明しているので、気になる方は是非読んでみてください。

個人的にこの問題が起こってzapとかに乗り換えた人が少なくないのかなと思ったり

Golang Weekly #168

GitHub - d4l3k/go-pry: An interactive REPL for Go that allows you to drop into your code at any point.

Goでのpry実装。
Rubyを書いていた時にbinding.pryを多用していたので、こちらも使っていきたい。

Benchmarking Go programs, part 2 - Tit Petric

Goにおける再帰処理、sync.Mutexでのdefer、sleepにおけるベンチマーキング。

  • 再帰処理は参照を用いることにより約30%の高速化
  • sync.MutexではdeferによるUnlockを行なう場合、メモリ確保を行なうので遅くなる、手動でやろう (ただし、Go1.9でdeferの最適化がなされているため、そんなに気にしなくてもいいかも)
  • 多くのgoroutine上でtime.sleepを実行すると、Go Schedulerの負荷が高くなりCPU使用率がえらいこっちゃになる

といったことを詳しくベンチマーク結果とともに書いてあります。

今回はここまで。
Go1.9では新しい追加機能の他、こういった細かい所のチューニングが楽しみですね💪

3連休を使ってしょうもないものを作ってしまった

素敵な3連休、皆様どうお過ごしでしょうか?

意識の高いエンジニア各位におかれましては、きっとエンジニアリングを磨き上げることに腐心なさっていることでしょう。

さて、そんな中「3連休中にアホなもの作りたい」という欲求を抑えきれずにアホなものを作ってしまいました。

その名も「go-kiriban」

github.com

なにこれ?

簡単に言うと「キリ番のプロセスIDがあればポップアップで教えてくれます」

f:id:syossan:20170717144027p:plain

なんで私はこんなものを作ってしまったのか・・・

技術的なお話

ここからは真面目に技術的な話をします。

今回のこのツールを作るに当たって、ザクッと以下のような仕様がありました。

  • goをデーモン化する
  • プロセスIDの取得
  • キリ番のプロセスIDがあれば何かしらで通知する

とりあえずこんな感じで実装進めていけばいけるでしょ、って謎の根拠を元に作り始めました。

goをデーモン化する

goのデーモン化については標準で備えているものがないため、自力でやる or ライブラリに頼るの二択になります。

自力でやるの選択肢を取る場合、

qiita.com

の記事が参考になるかと。

今回は楽にサクサクっとやりたかったので、ライブラリに頼ることにしました。

使ったライブラリはこちら。

github.com

コードの中身見たら分かるように、windowsdarwinfreebsdといった主要なOS毎に分けてあります。
とりあえずMacのみ対応させようと思ったので、launchdの仕組みを使ったdarwinのパッケージを使っていきます。

使い方はREADMEに書いてある通りで、Exampleの // Do something, call your goroutines, etc と書いてあるところに好きな処理を書いていく流れになります。

これで、goのdaemonizeは完了。

プロセスIDの取得

プロセスIDの取得にはこちらを使いました。

github.com

README・wikiともに詳しい説明がないので、気合でコード読んでいきましょう。

今回の場合では、 プロセスの一覧を取得プロセスのIDを参照 という2点を実現するために、以下のようなコードになりました。

processes := ps.Processes() // プロセスの一覧を取得

for _, p := range processes {
    fmt.Println(p.Pid()) // プロセスのIDの参照
}

go-psの中身はそんなに小難しくないので、使う分には困らないはず。

というわけでプロセスに関しても完了。

キリ番のプロセスIDがあれば何かしらで通知する

ここまではスイスイ出来たのですが、ここからがかなり難関でした。

最初、実装を考えた時に私の頭にあった通知形式はよくある右上にシュッと出てくる通知でした。

ただし、これをlaunchdに登録したプログラムから exec() で実行しようとすると、上手く動かないという問題にぶち当たりました。

原因としてはこの辺りだと思われるのですが、

apple.stackexchange.com

ちょっと提示されている解決法が良く分からなかったため、別のアプローチを取ることにしました。
それは display notification ではなく、 display dialog を使うアプローチです。

display dialog だと、表示の際にコントロールがダイアログに移ってしまうため、あまり使いたくなかったのですがとりあえず3連休中に作りきってしまいたかったために、止む無く使用することに。

こちらだと、launchdから exec() で実行しても動きます。

あとは、 giving up after 5 とかつけて良い感じに◯秒後にダイアログが消えるようにしたりとか。

完成

これでツールが完成しました!

実際は、同じプロセスIDの通知をしないようにoffsetつけたりとかしたのですが、その辺の細かいところはコード見てみてください。

たまには実用性とか何も考えずに、作ってみたいネタなツールを作ってみるのもありですね。

プログラミングは何も考えず楽しくやりましょう!!

depでの "is not within a known GOPATH" エラー in gvm

betaのgo1.9をちょこっと弄るためにgvmを導入したのですが、$GOPATHの扱いが $HOME/.gvm/pkgsets/go1.9beta2/global といった独自のものになります。

で、これの何が問題かというと、例えば普段設定している$GOPATHが $HOME/go だった場合には $HOME/go/src 直下にプロジェクトを作成してdepを使うと「$GOPATH内にねーよ」といって怒られます。

んじゃどうするかというと、とても簡単で gvm linkthis を実行します。

これを実行すると、現在のプロジェクトディレクトリをgvmでの$GOPATHの直下にlnしてくれます。
例えば $HOME/.gvm/pkgsets/go1.9beta2/global/src/hoge のような形ですね。

これでdepを実行すると無事動いてくれます👏

sqoopでhbaseへのimport時に好きな文字列をRowKeyにする

sqoopを使ってhbaseへimportする際にRowKeyを指定するには --hbase-row-key を使いますが、
通常はcolumnを一つ指定するか、カンマ区切りのリストで複数のcolumnを指定する形になります。

しかし、好きな文字列とcolumnの値を結合してをRowKeyにしたい場合はどうすればいいでしょう?

試しに以下のようなテーブルでやってみましょう。
DBはMySQLを想定しています。

テーブル名:user
カラム:
・id
・name

このテーブルからhbaseに以下のような形でimportしてみましょう。

RowKey:id_1_name_taro
CF:
・id
・name

それでは、sqoopでimportしてみます。
接続先の情報は省略しています。

sqoop import \
-- query "SELECT id, name, CONCAT('id_', id, '_name_', name) AS rowkey FROM user WHERE \$CONDITIONS"
--hbase-row-key rowkey

これでRowKeyが id_1_name_taro という形になります。
単純に CONCAT でRowKey用のカラムを作るって感じです。 あまり捻りのない感じですが、考え付くまでに時間がかかったので備忘録代わりに・・・