表参道.rb #14 でDigdagについてLTしてきました
8/4に開催された表参道.rb #14でLTさせていただきました。
ビアガーデン風ということで、会場提供していただいたSansan株式会社様のGardenというイベントスペースで開催され、飲み物、食べ物も無料提供していただきました。ごちそうさまでした。写真とっておけばよかった。
発表資料
Rubyを触る機会が以前にもまして減っているのですが、最近使ったDigdagにRuby APIがあったので、Ruby APIについてLTしました。
懇親会でもいろいろお話を伺いましたが、みなさんバッチ処理ではそれなりに困りごとがあるようだったので、興味を持って聞いていただけたのかなと思っています。
ひさしぶりのLT登壇で緊張しましたが、いくつか笑いも起こっていたので、自分も楽しんでLTできました。
資料はこちらです。
追記
資料中に「Ruby APIから設定した配列をYAML側でfor_eachを使って処理するのはできなさそう」というようなことを書きましたが、loopでできるのではというアドバイスをいただきました。
@ariarijp 有用な記事ありがとうございます。for_eachで配列が処理できないのはloopで回避できるかもしれません。参考 https://t.co/ptFAd2BHI9
— hiroyuki sato (@hiroysato) 2016年8月5日
参考として教えていただいたGistの通りにやってみたところ、lYAML内で配列を扱うことができました。
@hiroysato さん @smdmts さんありがとうございました!
このようにいろいろな方から反応をいただけるのも、ちょっと勇気をだしてコミュニティで発表することの利点ですよね。
mackerel-agent-pluginsにmackerel-plugin-php-fpmが含まれてないんだけど?と言われて調べた
まえがき
mackerel-plugin-php-fpm使いたいんだけど、CentOS使ってるんだけどまだyumで入ってこないんだよねー?と言われたので、ちょっと気になったので調べてみました。
このプラグインは私が作ったものなのですが、私の場合はgo build
したものを/usr/local/bin
に置くような雑運用かつUbuntu環境なのですが、実際のところどうなんでしょうか。
確認方法について
CentOSの環境が無いのでDockerで確認することにしました。Docker for Macがリリースされてから、よりDockerが気軽に使えるようになりましたね。
今回はmackerel-plugin-php-fpmのインストールだけを確認したいので、mackerel-agentはインストールしていません。
確認のための準備
準備と言ってもdocker build
だけです。イメージ名は何でもいいです。
$ docker build -t centos7-mackerel-agent-plugins .
確認してみる
無事にビルドできたら、さっそくdocker run
してみます。
docker run -it --rm centos7-mackerel Usage of mackerel-plugin-php-fpm: -metric-key-prefix string Metric key prefix (default "php-fpm") -tempfile string Temp file name -timeout uint Timeout (default 5) -url string PHP-FPM status page URL (default "http://localhost/status?json")
あら?インストールされているようですね。
もうちょっと確認してみる
インストールディレクトリを見てみましょう。
ここで察しがついているかたもいるかもしれませんが、もう少々お付き合いください。
docker run -it --rm centos7-mackerel ls -la /usr/local/bin ---snip--- lrwxrwxrwx 1 root root 33 Jul 21 14:55 mackerel-plugin-php-apc -> ../../bin/mackerel-plugin-php-apc lrwxrwxrwx 1 root root 37 Jul 21 14:55 mackerel-plugin-php-opcache -> ../../bin/mackerel-plugin-php-opcache ---snip---
おや。リンクになっていますね。/usr/bin
に実体がありそうな雰囲気です。
docker run -it --rm centos7-mackerel ls -la /usr/bin ---snip--- -rwxr-xr-x 1 root root 5131476 Jul 14 07:30 mackerel-plugin-php-apc -rwxr-xr-x 1 root root 4787124 Jul 14 07:30 mackerel-plugin-php-fpm -rwxr-xr-x 1 root root 5131476 Jul 14 07:30 mackerel-plugin-php-opcache ---snip---
実体はここにあって、ここにはmackerel-plugin-php-fpmもありますね。
なぜ/usr/local/binにインストールされないのか
0.19.4で変わったみたいです。
今までのものは互換性を保つために/usr/local/bin
にもおいてくれるようですね。
まとめ
インストールされてないと言っていたのが、インストールディレクトリが変わったこと以外の問題だったらちょっとわかりませんが、
Mackerelのように定期的にアップデートがあるプロダクトは、リリースノートもかかさずチェックしていくのがいいのかもしれませんね。
Raspberry PIとUSBマイクとMackerelを組み合わせて、室内の騒音レベルを可視化する
手近なものでできそうだったので、連休の合間にやってみました。
Raspberry Piの準備
Raspberry PIはすでに持っていたRaspberry Pi 2 Model Bを使います。
- 出版社/メーカー: Raspberry Pi
- メディア: エレクトロニクス
- この商品を含むブログ (10件) を見る
USBマイクはこれを使います。Raspberry Piでマイクを使うときはよく使われるものみたいですね。
SANWA SUPPLY MM-MCUSB16 USBマイクロホン
- 出版社/メーカー: サンワサプライ
- 発売日: 2009/05/13
- メディア: エレクトロニクス
- 購入: 2人 クリック: 3回
- この商品を含むブログ (6件) を見る
Raspberry PiでUSBマイクを使う例は、それなりに検索するとでてきますが、以下の記事を参考にしました。
soundmeter
音声信号処理についての知見もないので、あまりそこで時間をかけたくないのでsoundmeterというのをつかってみました。
インストールはREADMEに従えばよいでしょう。インストールするとsoundmeter
コマンドが使用できるようになります。
いくつかオプションがあり、RMSを取得するサンプリング時間や、結果の出力方法などを指定できます。
ちなみにRMSはRoot Mean Squareの略のようです。ざっくりイメージを掴むなら以下の記事を参考にしてみてください。
USBマイクのGAIN調整
soundmeter
が使えるようになったら、USBマイクのGAINを調整します。
計測したい場所にRaspberry PIをおいて、soundmeter
を実行しておきます。
オプション無しで実行すると、0.5秒ごとのRMSが表示されます。
もう一つターミナルを開いて、alsamixer
コマンドを実行し、マイクのGAINを調整します。
Mackerelで可視化
ここまででRaspberry PiとUSBマイクを使って騒音レベルが取得できるようになったので、あとはMackerelにメトリックを送信するだけです。
Raspberry PiへのMackerel導入については割愛しますが、以前Qiitaに記事を書いたので、多少は参考になるかもしれません。
カスタムメトリックを使う
Mackerelにメトリックを送信するには、カスタムメトリックの仕様にあわせてスクリプトを書く必要があります。
グラフ定義とメトリックを出力するスクリプトであれば、監視対象のホストで動けばどんな言語で書いてもいいと思いますが、
今回はRaspberry Piをつかっていることもあるので、素直にPythonで書いてみました。
これを適当なディレクトリーに置きます。今回は/opt/mackerel-check-scripts/soundmeter.py
に置くものとしておきましょう。
mackerel-agent.confに設定を追加する
[plugin.metrics.soundmeter] command = "/opt/mackerel-check-scripts/soundmeter.py"
上記の設定を追加し、mackerel-agentを再起動すると、数分後には以下のようなグラフが描画できていると思います。
実際のグラフを見ると途切れている箇所がありますが、時折soundmeterが以下の様なエラーを出してしまうので、おそらくこれが原因だと思いますが、厳密に計測したいわけでもないので、これは無視しています。
pi@raspberrypi:~ $ soundmeter 8 Traceback (most recent call last): File "/usr/local/bin/soundmeter", line 9, in <module> load_entry_point('soundmeter==0.1.3', 'console_scripts', 'soundmeter')() File "/usr/local/lib/python2.7/dist-packages/soundmeter/meter.py", line 311, in main m.start() File "/usr/local/lib/python2.7/dist-packages/soundmeter/meter.py", line 116, in start self.record() # Record stream in `AUDIO_SEGMENT_LENGTH' long File "/usr/local/lib/python2.7/dist-packages/soundmeter/meter.py", line 90, in record data = self.stream.read(FRAMES_PER_BUFFER) File "/usr/local/lib/python2.7/dist-packages/pyaudio.py", line 608, in read return pa.read_stream(self._stream, num_frames, exception_on_overflow) IOError: [Errno -9981] Input overflowed
まとめ
すでにRaspberry PiやUSBマイクなどの機器が手元にあり参考にできる記事も多く、Mackerelの扱いにもある程度慣れているので、連休の合間に2時間ほど作業しただけでできました。
最近はre:dashやAnsible、AWS Lambdaなど、Pythonで書かれたもの/書くもののお世話になる機会が増えてきたので、もうすこしPythonを書けるようになりたいなと思ったりもします。
re:dashがインストールできなくなったので調査した
7/3 22:30追記
re:dash開発者の @arikfr さんがこの記事を読んでくれたらしく。setuptoolsが修正されるまではこの記事で紹介したワークアラウンドを入れることになったようです。
なので、これからインストールする方にはこの記事は不要なのですが、記事は自分の活動記録としてそのまま残しておきます。
まえがき
Ubuntu用のセットアップスクリプトでre:dashをインストールしようとしたらインストールできなくなってたので調べました。
使用した環境はVagrantで起動したUbuntu14.04で、Vagrant Boxはubuntu/trusty64 (virtualbox, 20160627.0.0)
, re:dashのバージョンは0.10.1.b1834
です。
検証に使用したVagrantfile
# -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| config.vm.box = "ubuntu/trusty64" config.vm.network "forwarded_port", guest: 80, host: 9001 config.vm.provider "virtualbox" do |vb| vb.memory = "2048" end config.vm.provision "shell", inline: <<-SHELL sudo locale-gen ja_JP.UTF-8 SHELL end
セットアップスクリプト実行中のエラー
$ curl https://raw.githubusercontent.com/getredash/redash/master/setup/ubuntu/bootstrap.sh $ sudo bash bootstrap.sh
VMにログインし上記の様にスクリプトを実行したところ、途中は割愛しますがre:dashが依存しているモジュールを pip
でインストールするあたりでこんなエラーが出てしまいました。
Downloading/unpacking httplib2==0.9.2 (from -r requirements.txt (line 1)) Downloading httplib2-0.9.2.zip (210kB): 210kB downloaded Running setup.py (path:/tmp/pip_build_root/httplib2/setup.py) egg_info for package httplib2 Traceback (most recent call last): File "<string>", line 3, in <module> File "/usr/local/lib/python2.7/dist-packages/setuptools/__init__.py", line 14, in <module> from setuptools.extension import Extension File "/usr/local/lib/python2.7/dist-packages/setuptools/extension.py", line 11, in <module> from . import msvc File "/usr/local/lib/python2.7/dist-packages/setuptools/msvc.py", line 244, in <module> class PlatformInfo: File "/usr/local/lib/python2.7/dist-packages/setuptools/msvc.py", line 253, in PlatformInfo current_cpu = safe_env['processor_architecture'].lower() File "/usr/lib/python2.7/UserDict.py", line 23, in __getitem__ raise KeyError(key) KeyError: 'processor_architecture' Complete output from command python setup.py egg_info: Traceback (most recent call last): File "<string>", line 3, in <module> File "/usr/local/lib/python2.7/dist-packages/setuptools/__init__.py", line 14, in <module> from setuptools.extension import Extension File "/usr/local/lib/python2.7/dist-packages/setuptools/extension.py", line 11, in <module> from . import msvc File "/usr/local/lib/python2.7/dist-packages/setuptools/msvc.py", line 244, in <module> class PlatformInfo: File "/usr/local/lib/python2.7/dist-packages/setuptools/msvc.py", line 253, in PlatformInfo current_cpu = safe_env['processor_architecture'].lower() File "/usr/lib/python2.7/UserDict.py", line 23, in __getitem__ raise KeyError(key) KeyError: 'processor_architecture' ---------------------------------------- Cleaning up... Command python setup.py egg_info failed with error code 1 in /tmp/pip_build_root/httplib2 Storing debug log for failure in /root/.pip/pip.log
re:dashのセットアップスクリプトでいうと以下の辺りです。
原因を考える
ちょっと前に使った時は問題なかったのですが、なぜエラーが発生するようになってしまったのでしょうか。
いろいろ調べて回ったのですが、同様の事例や解決策を見つけられなかったのでsetuptools
のリポジトリを見てみました。
リリースを見てみると、最近リリースがあったようです(2016/7/03 10時現在では8時間前)
先ほどのエラーメッセージに/usr/local/lib/python2.7/dist-packages/setuptools/msvc.py
とあったので、該当のファイルが追加されたPull Requestをみてみます。
たぶんこのあたりでなんかあるんだろうなと思ったので、セットアップスクリプトを以下のように変えて再度実行します。
@@ -29,7 +29,7 @@ apt-get -y update apt-get -y dist-upgrade apt-get install -y python-pip python-dev nginx curl build-essential pwgen -pip install -U setuptools +pip install -U setuptools==23.1.0 # redash user # TODO: check user doesn't exist yet?
再実行
再実行時は念のためVMを破棄し、再度作成しなおしたVM上でスクリプトを実行したところインストールが問題なく完了し、 http://localhost:9001/ にアクセスすることが出来ました。
まとめ
re:dashは頻繁にアップデートされるため、たまにインストールがうまくいかないことがある印象があるのですが、今回はsetuptoolsの問題でした。
おそらくsetuptoolsもそのうち修正されるんじゃないかと思いますが、re:dashを使おうとして同じような問題にぶつかった方がこの記事を参考にしていただけたらうれしいです。
iOS9のWebView内でTwitterのシェアボタンをクリックしたらiOS標準のダイアログで投稿したい
まえがき
同僚さんがタイトルに書いてあるようなことをやりたいけどできないと言っていたのでちょっと調べてみました。
やってみた
正しいやり方かどうかは別として、こんなやり方になりました。
import UIKit import Social class ViewController: UIViewController, UIWebViewDelegate { @IBOutlet weak var webView: UIWebView! let twitterIntentUrl = "https://twitter.com/intent/tweet" let initialUrlString = "http://ariarijp.hatenablog.com" override func viewDidLoad() { super.viewDidLoad() let url = NSURL(string : initialUrlString) let urlRequest = NSURLRequest(URL: url!) webView.delegate = self; // WebViewの初期表示 webView.loadRequest(urlRequest) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { let absUrl = request.URL?.absoluteString // リクエストされたURLがTwitterのシェアボタンっぽいものだったら、Social.frameworkでダイアログを表示する if absUrl!.containsString(twitterIntentUrl) { // アカウントの設定が済んでいれば投稿ダイアログ、設定が済んでいなかったらアラートを表示する // 参考: http://www.brianjcoleman.com/tutorial-share-facebook-twitter-swift/ if SLComposeViewController.isAvailableForServiceType(SLServiceTypeTwitter){ // URLからシェアに使うテキスト、URLを取り出す let tweetUrl = getQueryStringParameter(request.URL?.absoluteString, param: "url") let tweetText = getQueryStringParameter(request.URL?.absoluteString, param: "text") let twitterSheet:SLComposeViewController = SLComposeViewController(forServiceType: SLServiceTypeTwitter) twitterSheet.setInitialText("\(tweetText!) \(tweetUrl!)") self.presentViewController(twitterSheet, animated: true, completion: nil) } else { let alert = UIAlertController(title: "アカウントエラー", message: "Twitterにログインしてください", preferredStyle: UIAlertControllerStyle.Alert) alert.addAction(UIAlertAction(title: "閉じる", style: UIAlertActionStyle.Default, handler: nil)) self.presentViewController(alert, animated: true, completion: nil) } return false } return true } // URLから指定したパラメータを文字列として取り出す // 参考: https://gist.github.com/gillesdemey/509bb8a1a8c576ea215a#gistcomment-1483938 func getQueryStringParameter(url: String?, param: String) -> String? { if let url = url, urlComponents = NSURLComponents(string: url), queryItems = (urlComponents.queryItems) { return queryItems.filter({ (item) in item.name == param }).first?.value! } return nil } }
StoryboardでwebViewを配置して、このViewControllerにOutletを追加してあるのが前提です。
また、はてなブログのURLで動作確認してますが、HTTPSでは無いのでATSの設定をいじったりしてます。
動作確認
動かしてみるとこんな感じです。
Twitterにログインしていない状態でアプリ内WebViewでシェアボタンをタップ
Twitterにログインした状態でアプリ内WebViewでシェアボタンをタップ
今回のような実装を入れなかった場合(デフォルトの挙動
まとめ
雑な感じで「できないことはないでしょう」と言った手前ムキになってやった感がありますが、思ったようなことはできたのでよかったです。
もっと効率が良いやりかたがあれば、Twitterなんかでぜひ教えて下さい。