読者です 読者をやめる 読者になる 読者になる

tofucodes diary

にほんごのほう

CloudWatchでSNSのメトリクス取得につまずいた話

SNSの通知の成功数・失敗数を集計したかったんです。

前任者のコードを見てみたら

// SNSは通知の成功数・失敗数が分からないため0を入れておく

とコメントがあったんだけどそんなことはなくw

CloudWatchでSNSのメトリクスを見ればちゃんと確認できました。

SNSはPush通知で使っているため、iOSAndroidそれぞれの通知成功数・失敗数が取得したかったのですが

ディメンションでPlatformを指定してもどうにも取得できない。

Amazon Simple Notification Service は以下のディメンションを CloudWatch に送信します。

上記リンクにもこう書いてあるのに…。

でなぜ取得できなかったのか結論から言うと、SNSのTopicを使ってPush通知を送っていたから、でした。

以下は取得できるメトリクスをAWS-CLIで確認した結果です。

TopicNameの方は取れてますが、Platformの方は取れてませんね。

$ aws cloudwatch list-metrics --namespace 'AWS/SNS' --dimensions "Name=TopicName,Value=トピック名"

{
    "Metrics": [
        {
            "Namespace": "AWS/SNS",
            "Dimensions": [
                {
                    "Name": "TopicName",
                    "Value": "トピック名"
                }
            ],
            "MetricName": "DwellTime"
        },

    (省略)

    ]
}
$ aws cloudwatch list-metrics --namespace 'AWS/SNS' --dimensions "Name=Platform,Value=APNS"

{
    "Metrics": []
}

試しにTopicではなくSNSのApplicationに対して通知をしてみたところ、Topicメトリクス以外のフィルタについても確認することができました。

AWSコンソールの表示も以下のように変わりました。

before

f:id:tofucode:20151030213415p:plain

after f:id:tofucode:20151030213337p:plain

自作ライブラリをbowerに登録してみた

以前作ったショボいライブラリが会社の人にバレて「npm install、bower installでインストールできるようになるのはまだできない認識であってますか?」って言われて微妙な反応したら

expect(response).to.eq(‘はい、そちらはまだです’);

というチャットが送られてきたのでbowerに登録してみた(パワハラです)

流れ

こんなかんじ。というかこれだけ

  1. 登録したいGithubレポジトリを決める
  2. bower.jsonを作成する
  3. Git tagでversioningする
  4. bower registerする

1. 登録したいGithubレポジトリを決める

今回登録したのはこれ

以前このブログでも取り上げたので一応再掲

2. bower.jsonを作成する

$ bower init

そしたら対話形式でいくつか質問に答えていけば自動でbower.json作成完了

自宅のbower1.2.7では以下のような質問内容

[?] name: dateformatjs
[?] version: 1.0.0
[?] description: Extension of the Javascript Date object with a minimum function for shaping the date.
[?] main file: dateformat.js
[?] keywords:
[?] authors: Toru Furuya t.furuya825@gmail.com
[?] license: MIT
[?] homepage: https://github.com/torufuruya/DateFormat.js 
[?] set currently installed components as dependencies? Yes
[?] add commonly ignored files to ignore list? Yes
[?] would you like to mark this package as private which prevents it from being accidentally published to the registry? (y/N)
[?] would you like to mark this package as private which prevents it from being accidentally published to the registry? No

3. Git tagでversioningする

remember to push your Git tags!

本家にこれしか書いてなかったのでやり方書いてくれればいいのにとか思いつつ

$ git tag v1.0.0
$ git push origin v1.0.0

version指定はsemver方式でやれ、みたいなことが書いてあるんだけど要は vX.Y.X のフォーマットなら大丈夫ぽい

4. bower registerする

さいごに登録

$ bower search XXXXX  //一応既に同名のパッケージがないか確認
$ bower register <my-package-name> <git-endpoint>

bower infoで確認しておしまいおしまい

そういえば

javascriptで日付を扱う際の近頃のトレンドは Moment.JS らしい

http://momentjs.com/

SourceMapを用いてOSSのライセンス表記を外に出す方法

OSSライセンスの明記をSourceMapで回避しちゃおうという話。

例えば

複数のjsファイルを結合したプロダクトのコードをminifyしてCDNとかに置くパターンを想定。 こういう場合おそらく以下のようなケースがあると思うんですよ。

  • 各jsファイルのminifyされたものを結合する
  • 全てのjsファイルを結合した後の1ファイルをminifyする

前者のケースの場合は、各min.jsにライセンスが表記してある必要がありますし(まあ大体のOSSライブラリはこうなってるかもだけど)、後者のケースでも結局minifyする時にライセンス表記を消さないようにしないといけないんですね。 自分のチームじゃないんですが、前者の方法でライセンスを保持してるチームも実際にあります。

で自分のとこはどうしようかなあと思っていたところ、チームの先輩がタイトルにあるSourceMapを用いたライセンスの表記の方法を提案してくれました。 SourceMapを用いると以下の2点のメリットを得ることができます。

  1. minify後の最終ファイルにライセンス文を含めなくて良い
  2. デバッグしやすい

minify後の最終ファイルにライセンス文を含めなくて良い

らしい。としか言いようがないのですがw このあと触れますがブラウザでminify前のjsを参照できてそっちにライセンスが表記してあれば大丈夫「らしい」です。(ご自身で調べてみることをおすすめしますmm) 自分も調べてみたのですが、残念ながらそれっぽい情報には辿り着けませんでした。 でもpixivでも同じ方法が取られている「らしい」です。 ファイルの大きさ的にはライセンス文の分だけ少なくなるくらいであまりここにはメリット無いかなと、あくまで自分のチームのプロダクトではそう感じました。

デバッグしやすい

これはSourceMapを利用したことがある人なら分かることですが、ブラウザでデバッグがしやすくなります。 具体的にはminify前後のファイル(sample.js/sample.min.js)とSourceMap(sample.min.js.map)を同じパスにデプロイした状態でブラウザでminify済みファイル(sample.min.js)を読み込みます。すると読み込んでるのはminify済みのファイルだけなのに、ブラウザのデバッグツールではminify前のファイル(sample.js)も参照することができるようになります。そのminify前のファイルにブレイクポイント差し込むこともできちゃいます。すばらしいですね。

方法

ほぼほぼ前の項目で書いてしまったんですが一応まとめとして。

  1. minifyする時にSourceMapを書き出すようにする
  2. minify後の最終ファイルと同じパスにminify前のファイルとSourMapもデプロイする

僕のチームでは結合&minifyはGruntで自動化してるのでこれ使ってSouceMapを書き出してデプロイとかしてます。

お願い

今回記載した内容についてもし間違いが含まれてましたら、コメント等でご指摘いただけたら幸いです。

追記

1日空けて考えてみたらちょっと思うところがあったので追記。 たぶんSourceMapの良い点としてminifyしてもコードを「可読性の良い状態で」公開することができることなのかと思いました。思い返せば、今回のアドバイスをくれた先輩も常日頃コードは公開すべきみたいな立場にいたなぁ、、、とw

なので今回の内容の本質はライセンスどうこうではなく、コードを公開するという点だったのかもしれませぬ。

さらなる追記

t-wadaさんからこのようなご指摘を受けまして、、、まさに言いたかったことをおっしゃってくれましたw ということでタイトルが誤解を招くような感じを受けるので修正しました。

t-wadaさんありがとうございますー。

FastClick適用下でのチェックボックスにおける問題

業務でデザイナーから受け取ったツールキットを取り込んだ際に、チェックボックスが期待通りに動かないからもしかしてFastClickのせいかなと思って調べたまとめ。

そもそもFastClickとは

スマホではダブルタップを判定するためにタップしてからイベント発火するまで300msの待ちがある。 FastClickはその待ちを消してタップが早く反応するようにするもの。

問題

例として以下のようなHTMLがあるとする。

<label>
  <div>
    <input type="checkbox">
  </div>
</label>

上のHTMLはのエリアをタップするとチェックボックスが反応することが期待されてる。 しかしiOSにおいて期待通りの動きにならず、以下の対応もしてみたがiOS5/6/7のうち6/7は改善が見られなかった。

もしかしたらと思い、FastClick.jsを使わないようにしてみたらiOSでも動いたのでFastClickを調べてみた。

原因

FastClick本家にもissueが上がっていた。 このissueの内容を見てみると以下のような場合において正常に動作するよう対応がされたぽい。

<label><input type="checkbox">Checkbox</label>

もしくは

<label for="checkbox1">Checkbox</label>
<input type="checkbox" id="checkbox1">

でもこの対応だとlabelタグの外側にinputタグを配置するか、labelタグの中に含める場合でも 1階層下 までにinputタグがないといけないらしく、前述したHTMLのようにlabelタグから深い階層にinputタグがあるとうまく動かなかった。

で新たなissueが作られてて

この中では 「深い階層でもいけるようにできるか調べてみるぜ!」 的なことが当初言われてたあとに、 「cssいじったら動いたしこっちのがコスト低いからcssいじってちょ!」 っていう結論に至ってました。 でどうcssをいじればいいかというと

label > * { pointer-events: none; }

ためしに上記のcssを前述のHTMLを使ってる画面に反映させてみたところ、見事に動きました。

結論

  1. FastClickを使うのをやめる (一番簡単だけどできればしたくない)
  2. cssに上述のやつを追加する
  3. inputタグがlabelタグの 2階層 以上深くならないようにHTMLを変更する

DateFormat.js

Javascriptで日付を整形するのめんどくさい人向けにライブラリ作りました。(俺得)

例えば “1989年8月25日” みたいな日付を取得するためには以下のような感じになるかと思います。

var d = new Date('1989/8/25');

var year = d.getFullYear();
var month = d.getMonth() + 1;
var date = d.getDate();

console.log(year + '年' + month + '月' + date + '日');

いちいち変数に入れて無駄に行数増やしてる感はありますが、getMonth()で+1するのとかよく忘れます、はい。

上の例は1989/8/25固定でやってるから微妙ですが、例えばサーバから取ってきたタイムスタンプを特定のフォーマットにして表示したい時とか。

ということで今回このような日付のフォーマットを簡単にできるライブラリを作ってみました。

github.com

PHPのdate()みたいにフランクにフォーマットできるのを目指してます。

完全独立なグローバル関数でいいかなーとか、jQueryプラグインにしてみようかなーとか最初は思ったんですが、

JavaScriptで日付使う時はまあDateオブジェクトだし、Dateオブジェクトのprototpyeにぶっこんじゃえーって軽いノリで実装しました。

こんな感じで使えます。

var d = new Date(1388599445000);

d.format('Y-m-d H:i:s');  //=> "2014-01-02 03:04:05"

d.format('n/j h:i')  //=> "1/2 3:04"

これを使った場合、最初の例は下のような感じで書けるようになります。

var d = new Date('1989/8/25');
d.format('Y年m月d日');

やってることはものすごい簡単で特定の文字を正規表現でreplaceしてるだけですね。

githubにこういうの公開するの初めてなのでライセンスとか書くのちょっと恥ずかしかったですw

MITって書いとけばいいかなみたいなw

あとテストも書いたんで、travisとか使ってみました。

初めて使ってみたのですが、無料であそこまでできるのすごいすね。

ライブラリ自体は超たいしたことしてないし、他に同じようなの作ってる人たくさんいるだろうし、むしろこういう初めてやることができて良かったです。

と、今回は経験として誰得なライブラリを作ってしまいましたが、いづれは誰かの役に立つようなモノも作れたらいいですねー

[追記]

がっつりおんなじ思想で作られたライブラリを後日ふと見つけましたw

すばらしいです。拝承。

rewish.jp