YAMAGUCHI::weblog

ジャイトニオ猪場のはからいで、全財産を失いました。トランスマスターケンちゃんこと、剣持です。

特定のコミットメッセージを持つコミットの詳細なコミットログを一覧で見る

はじめに

こんにちは、Stackdriver担当者です。いまGoのコミットを調査していて必要になったので調べていました。

ユースケース

Go本体にコントリビュートする場合、コミットメッセージの形式が次のように定められています。

math: improve Sin, Cos and Tan precision for very large arguments

The existing implementation has poor numerical properties for
large arguments, so use the McGillicutty algorithm to improve
accuracy above 1e10.

The algorithm is described at https://wikipedia.org/wiki/McGillicutty_Algorithm

Fixes #159

最初の行では変更を加えたパッケージ名をまず書いた後に、コロンを挟んで1行でコミット内容を説明します。空行を挟んで、2パラグラフめ以降に詳細なコミットメッセージを書いていくわけです。

今回、cmd/compile パッケージに加えられたコミットのコミットメッセージをすべてみたいという要求があり、結果次のようにして一覧しました。

% git log --oneline --grep "cmd/compile" | cut -f 1 -d ' ' | xargs git show --abbrev-commit --quiet

この様に表示されます。

% git log --oneline --grep "cmd/compile" | cut -f 1 -d ' ' | xargs git show --abbrev-commit --quiet
commit fbde753a58
Author: Keith Randall <keithr@alum.mit.edu>
Date:   Tue Jun 25 22:24:34 2019 -0400

    cmd/compile: make duplicate anonymous interface output deterministic
    
    Taking over CL 162240, the original CL hasn't been making progress.
    I just took the parts that fix the immediate issue. I left the
    signatslice changes out, I don't think they are necessary.
    
    Fixes #30202
    
    Change-Id: I5b347605f0841dd925d5a73150b8bf269fa82464
    Reviewed-on: https://go-review.googlesource.com/c/go/+/183852
    Run-TryBot: Keith Randall <khr@golang.org>
    Reviewed-by: David Chase <drchase@google.com>
    TryBot-Result: Gobot Gobot <gobot@golang.org>

commit 4ea7aa7cf3
Author: Cherry Zhang <cherryyz@google.com>
Date:   Tue Jun 25 14:48:04 2019 -0400

    cmd/compile, runtime: use R20, R21 in ARM64's Duff's devices
    
    Currently we use R16 and R17 for ARM64's Duff's devices.
    According to ARM64 ABI, R16 and R17 can be used by the (external)
    linker as scratch registers in trampolines. So don't use these
    registers to pass information across functions.
    
    It seems unlikely that calling Duff's devices would need a
    trampoline in normal cases. But it could happen if the call
    target is out of the 128 MB direct jump limit.
...

他にもっといい方法があったら教えてください。

追記 (2019.07.08 19:00)

いくつか助言をいただいたので、その後諸々検討してみました

% git log --oneline src/cmd/compile | wc -l
3951

% git log --oneline --grep "cmd/compile" src/cmd/compile | wc -l
3673

% git log --oneline src/cmd/compile | grep "cmd/compile" | wc -l
3654

% git log --oneline --grep "^cmd/compile" src/cmd/compile | wc -l
3080

この中でどれが自分の本当に求めているログに絞れているのかと考えてみると、おそらく3番目のもので、理由は

  1. Goのコミットメッセージの規約は守られていると仮定して、--grep="cmd/compile" としてしまうと、2パラグラフめ以降にだけ cmd/compile が入っているものが含まれてしまう。
  2. "^cmd/compile" としてしまうと、1行目の対象パッケージの部分で、 runtime, cmd/compile: となっているようなコミットが漏れてしまう。

が挙げられる。したがって今回自分がみたいログを見ようと思ったら

% git log --oneline src/cmd/compile | grep "cmd/compile" | xargs git show --abbrev-commit --quiet

が正解になると思う。

GoogleのDeveloper Relationsチームは何をしているのか

はじめに

こんにちは、Stackdriver担当者です。

これまで「Developer Relationsは何をする組織なのですか」「Developer Advocateってどんな仕事をしているのですか」といった質問をしばしば受けてきました。都度考えながら答えていたのですが、今後のためにこの記事にまとめておこうと思います。

The Business Value of Developer Relations: How and Why Technical Communities Are Key To Your Success

The Business Value of Developer Relations: How and Why Technical Communities Are Key To Your Success

Developer Relations とは何か

XXX Relationsとは何か

自分は Developer Relations を語る前に、まず世の企業内で見られるような他の「XXX Relations」というタイトルの組織について考えていくと整理しやすいのではないかと考えています。

  • PR (Public Relations; 広報): 一般大衆に向けて企業の情報を伝達し、同時に一般大衆から意見や情報を受け入れるための組織
  • IR (Investers Relations): 投資家に向けて企業の経営状況や財務状況を伝達し、同時に株主を主とした投資家からの意見や情報を受け入れるための組織
  • GR (Government Relations): 企業が政府や行政と関係を結び、企業が実現しようとしている目標に関係する法令や規制に関してのスムーズな意見交換を実現する組織

とこのように「XXX Relations」と呼ばれる組織は名前の通り 対象の人間や組織と関係を作り、そこで必要とされる情報を伝達し、同時に意見や情報を受け入れる 組織であるとわかります。

Developer Relations の定義

先の話を前提として、自分はDeveloper Relationsを次のように定義しています。

開発者や企業に向けて自社関連技術を伝達し、同時にそれらに対する意見や情報を受け入れるための組織

これを分解して考えていきます。まず前半の「開発者や企業に向けて自社関連技術を伝達し」の部分。これに関しては注意をしないといけないと考えています。

このツイートでも書いていますが、よくDeveloper Relationsでは開発者イベントを開催したり、登壇したりするだけが仕事だと思われているようですが*1、それは一部でしかありません。

開発者に自社関連技術を伝える仕事としてはイベント関連を含めて多岐に渡ります。たとえば自分が担当しているDeveloper Advocateでは次のような仕事に関係しています。

  • 開発者イベントの企画、開催
  • 開発者イベントでの登壇
  • 開発者コミュニティとの連携
  • 技術資料の作成(公式ドキュメント、ブログ、動画など)
  • サンプルコード、参照実装、デモの提供
  • クライアントライブラリ、SDKAPIの提供
  • OSSの開発
  • PRやGR、ビジネス開発などに対する技術面での後方支援

また後半の「自社関連技術に対する意見や情報を受け入れる」に関しても活動も多く

  • 各種標準団体や重要なOSSに参加・連携
  • 主要ユーザー(企業等)との定期的なディスカッション、ヒアリング
  • 新規技術や機能を導入する企業への技術支援

上記で集めた意見や情報を自社製品や関連技術の改善につなげるために

  • 社内の他の技術職(ソフトウェアエンジニア、セールス系の各種エンジニアなど)との技術・情報の共有
  • プロダクトマネージャーやソフトウェアエンジニアと製品や機能に関してディスカッション、PRDやDesign Doc*2へのフィードバック
  • GDEへの情報提供含めたディスカッション

といった仕事も多く行っています。(むしろ日常業務はこれらがすごく多い)*3

これらを見ると他の組織と重複する仕事も多いですが、GoogleのDeveloper Relationsチームでは「最終的に開発者のメリットになるのか」という点が最重視されていて、営業的な数値目標で意思決定がされるわけではありません*4。個人的にはこの点において営業組織との棲み分けが強く働いていると思います。社内にいながら、ときには開発者視点でみて、外部開発者に導入を積極的には勧めない、あるいは様子を見るように伝えることもあります。また外部開発者の視点で開発チームに修正を求めるフィードバックも多々行います。

Google の Developer Relations に所属する役職

Google Careers のサイトに Developer Relations に属する役職などの説明動画があります。(動画自体は少し古いですが、内容は変わっていません)

www.google.com

Developer Relationsチームに所属する職種は細かくみるとこれよりも多いのですが、主要な職種は次のとおりです。

  • Developer Advocate
  • Developer Programs Engineer
  • Developer Program Manager
  • Technical Writer

これらの役職はおおよそ次のように分かれています。

  • Developer Advocate (DA): 対外的な仕事が多く、担当領域に関してイベントでの登壇や外部の開発者への技術支援、担当製品のフィードバック収集などをよく行う。
  • Developer Programs Engineer (DPE): SDKやサンプルコードの開発など。
  • Developer Program Manager: コミュニティ(例: GDGGCPUG)との連携やオフライン/オンラインイベントの開催などを重点的に行う。
  • Technical Writer: 公式ドキュメント(Google DevelopersGoogle Cloudの各種ドキュメント)の執筆

これらがすべてきっちりと分かれているわけではなくて、たとえば自分はクラウドチームのDAですが、GoやOpenCensusといったOSSのコミュニティとの連携を業務の中でも重視していますし、サンプルコードやPoCコードを書くことが多々あります。

WebチームのDAのえーじさんはいまはWebAuthNの普及に務めつつ*5、長年一貫してWeb関連のコミュニティ支援を行っています。

DPEである@yuichi_araki(通称: 課長)は、メイン業務ではRoomの開発をしつつ、コミュニティでの登壇やハンズオン講師なども必要に応じて行っています。

Program Managerであるたくおさんも、コミュニティ支援やイベント企画だけでなく、デザイン系のイベントでの登壇などもよく行っています。

このように各職種に大きな枠はありつつも、最終的に「ユーザーである外部開発者と社内の開発チームをつなぐ橋」として成立すれば、自分が実行したほうが良いと思ったことを裁量を持ってなんでもできるというのがGoogleのDeveloper Relationsです。

おわりに

そもそもこれを書こうと思った理由は先日開催されたイベントの名前を見て面白さを感じたからです。

ここでは「SA (Solution Architect)」の人たちが集まっていたようですが、各社でSolution Architectの職務の定義は違っているはずです。X社ではプリセールスという認識で、Y社ではポストセールスとして扱われていたりするでしょう。そうした人たちが同じ職種であるということで集まって活動内容をシェアするというのは、その職種に共通する性質を知る近道なのかもしれません。

最近は日本でもDeveloper Relationsという組織を持つ企業が増えてきました。先に挙げたPR、IR、GRが会社の特性に合わせて異なった活動をしているのと同様に、各社のDevRelの活動は大まかには近しいとしても、企業によって変わってきます。しかし、その「大まかに近しい」活動の内容が「重要である」と認識されれば、個人的には自分のキャリアパスも広がるので嬉しい限りです。

日本でもDevRelConが開催されていますが、こうした活動が広がってDeveloper Relationsの重要性が認識されることを願っています。

参照

*1:実際にイベントでそのように聞かれたことが多々あります

*2:Product Design Doc; プロダクト要求仕様書、Design Doc; 設計仕様書

*3:他にも上記以外にやってそうだけど自分がパッと思いついたのはこれくらい

*4:目標設定に関しては営業的な数値目標を持つことを禁止しているわけではなく、優先度が違うという意味です。

*5:リンク先のWebAuthNの記事もえーじさんが書いたものですね

Go Conference 2019 SpringのPaperCallを初めて使ってみた感想+α

はじめに

こんにちは、Stackdriver担当者です。先日、Go Conference 2019 Springのセッションの応募にはじめてPaperCallというCfP as a Serviceを使ってみました。

www.papercall.io

使ってみての感想がいくつかあったので忘れないうちにメモしておこうと思います。

運営として

これまでGoConでのCfPはGoogle Formで作ったテキストエリアにただAbstractとDescriptionの中間くらいの分量のものを書いてもらって、その内容だけで判断していたのですが、今後のイベントとしての方向性を考えてPaperCallを使ってみました。

運営としてPaperCallがいいなと思った点は

  • コミッティーがセッションに求める内容をCfP Descriptionをきちんと書ける
  • 世界のコミュニティーに直接リーチできる

の2点です。

CfP Descriptionが書ける

今回のCfPでは、セッションとしてどういう内容を期待しているか、を書いていました。(そして応募されたProposalのうちの かなりの割合 がそれを無視していましたがw)

Selection Criteria Proposals will be reviewed based on the selection criteria below.

Relevance: The talk is relevant to the Go community. GoCon is not a general software conference, our audience wants to hear about topics that relate to the Go programming language.

Clarity: You’ve clearly explained what you are going to talk about.

Correctness: You’ve demonstrated knowledge of your topic. You don’t have to be an expert, but you are expected to be speaking from experience.

Achievability: You’ve thought about how to present your material in the time available. Impact. The goal of the talk. What new idea, technique, tool, or information will the audience leave your presentation with? Note: This clear selection criterion is based on GopherCon’s one. Thank you.

今回は8人のレビュワーが全Proposalを5段階評価をしたあとに、その平均点と標準偏差を取り、各トークフォーマットごとに平均点を降順にならべて、高得点のものから採用としていきました。(標準偏差はばらつきが大きいものだけ各人の評価を確認するためだけに使用)

やはり採択された中でも得点が高かったもの(4点以上)は、上記の条件すべてに当てはまっているものが多かったです。やはりGo Conferenceなので、上にあるように

  • そのセッションがどうGoに関係しているのか
  • そのセッションはどのような問題を解決してくれるのか
  • そのセッションで登壇者が伝えたいことの独自性はなにか

こうしたものが伝わってくるようなProposalは、それを読むだけでワクワクしましたし、ぜひ発表を聞きたいと感じ自ずと点が高くなりました。

世界のコミュニティーに直接リーチできる

PaperCallを利用したもう一つの理由は、多くの海外のカンファレンスでもそれがCfP用プラットフォームとして利用されていて、海外のエンジニアがPaperCallに公開されているイベントには、まず勢いで登録しているからです。

今回CfP Descriptionなどをほとんど英語で書いたのも、そうした海外のエンジニアに向けて情報を伝えられるように配慮した結果でした。

で、今回のGo Conferenceでの結果はどうだったのかというと、数は少なかったものの、きちんと応募がありました!そしてその少ない応募のうち2名は海外から参加されます!これは本当に嬉しいことで、すでに登壇者の方とはメッセージでやり取りをしています。

一人は「スピーカーに渡航費等の補助はあるのか」と質問してきたのですが、残念ながらいまのGoConではそれは賄えないと伝えると、それでも来てくれると言ってくれました。本当に嬉しい限りです。もう一名の方もビザの準備等がありまだ参加が確定しているわけではないのですが、それでも楽しみにしていると言ってくれました。

こうした方々の参加が今後ますます増えてくるようなイベントにしたいですね。スピーカーの渡航費補助などもできる仕組みを整えたいなと考えています。(イベント自体の有償化も視野に入れて)

応募者側として

逆に応募者側として何がいいかなと思ったときに次の内容が挙げられるなと思いました。(自分も1セッション応募した)

  • 応募者側としてタイトル、概要(Abstract)、セッション詳細(Description)、追加情報(Note)をきちんと分けて書ける
  • 同じProposalを複数のイベントに登録できる

各セクションが別れている

Proposalの書き方は、学会のポスターセッションなどに近い感覚でした。そうしたものに慣れていない人にも、タイトル→概要→セッション詳細→追加情報という形でフォームが広くなっているので、セッション自体を考えるプロセスにも使えるのが良かったです。

その中でもやはり概要とセッション詳細が肝だなと思いました。概要に書く内容は、セッションスライドで言えば、最初あるいは最後のスライドにくるような「何を伝えるセッションなのか」ということ。ここを先のCfP Descriptionに一致させたあとに、実際セッション詳細で、細かな内容を記述できるわけです。

今回の応募者の中にはトークフォーマットに合わせて、各内容をどれくらいの時間をかけて話す、ということまで説明してくれていた人もいました。そういった内容があればProposalのレビューをする際にも、セッションの様子をより具体的にイメージすることができるので助かるなと実感しました。

同じProposalを複数のイベントに登録できる

今回、Go Conference 2019 Spring と Go Conference 2019 Summer in Fukuoka のCfPの期間がかぶっていました。 どうなるかわからなかったので、GoConとGoCon Fukuokaには両方同じTalkを登録しました。Submissionごとにあとで編集できるので、出してから変更すればいいのですが、自分の得意なテーマがある場合にはそれを様々なイベントに対してチャレンジできるのは便利だと思いました。

早速 GoCon 2019 Spring の Reject Conf もあり、そこでもPaperCallを使うようなので、残念ながら通らなかった人も、PaperCallの機能を使ってそちらに登録してみてもらいたいです。

コミッティーとしての感想

Proposalをたくさんいただいた中で、やはりもうちょっと改善してもらいたいなと思うProposalはあって、何段階かあったのですがつぎのようなものが多かったです。

  1. セッション詳細がない or 雑
  2. 応募者が登壇しなければならない理由がわからない

まず1つめの「セッション詳細がない or 雑」に関して言うと、前者は自明として、後者はどういうものかといえば、ブログか何かのURLが貼ってあってそれでおしまい、というようなもの。レビュワーもかなりの数(今回のレビューで言えば合計で5万字くらい読んでます)のProposalに目を通すので、その中でそういう応募があれば、熱意を感じられず加点をする気持ちが起きません。ブログのURLだけが貼ってあるものを見たときには私は中身も確認せずに「このブログ記事をシェアすればいいだけなのだから、イベントで登壇枠を作る必要はない」と判断しました。

2つめの「応募者が登壇しなければならない理由がわからない」に関しては、ライブラリやツールなどの基本的な使い方の説明、などです。ドキュメントに書いてあるような内容しかセッション詳細で読み取れないときには、やはりこれもドキュメントをシェアすれば済んでしまう話になります。

今回コミッティーとして分量があるProposalを多く読み、あらためてProposalに込められた熱意というのは大事だなと実感しました。今後PaperCallやそれに類似したサービス使うイベントは増えてくると思いますが、このサービスのおかげで様々なイベントでのセッションの質もあがるのではないかという期待が湧いてきました。

今回は初めてのPaperCallでしたが、次回は2回めで運営側も参加者側も慣れていると思うので、今回よりももっと充実した投稿が増えることでしょう。早くも秋のイベントが楽しみです。

追記 2019.04.25 09:57AM

普通にウェブサイトにはProposalのタイトルと概要だけ載せたのですが(そうしないと発表内容全部公開になってしまうので面白くない)、何がウェブサイトに記載されるか書いていなかったため、何人かの方から「詳細も載せてほしい」「概要を変更させてほしい」というリクエストが来ました。 これらに関しては運営側がCfP Descriptionにその旨を書いていなかったのが悪いので反省しています。しかし詳細を載せてしまうとセッション内容が全部わかってしまい、個人的には興ざめになってしまうので、そのリクエストはお断りしました。また概要を変更するのも、人手が圧倒的に足りないので都度修正する手間などを考えてお断りしています。

右綴じ書籍のスキャン済みPDFをKindleで読む

はじめに

こんにちは、Stackdriver担当者です。海外旅行に向けて準備をしているのですが、Kindleに読みたい書籍をLinuxの端末のみを使って入れるのに苦戦したのでメモを書いておきます。

TL;DR

  • 右綴じ書籍対応のためにPDFを全部逆順にした(pdftk 使用)
  • PDFのサイズ圧縮にGhostscriptを使った
  • これでなんとか Send to Kindle が使えた

PDFのページを逆順にする

Kindleアプリは使ってないのでわかりませんが、ハードウェアのKindle*1では、典型的な日本語の書籍(縦書き右綴じ)の書籍を開くのに対応していません。

そこで仕方なく、PDFページを全部逆順にしたあとに末尾ページ(=元ファイルの先頭ページ)から戻していくことで右開きを実現しました。

$ pdftk input.pdf cat N-1 output output.pdf

ここで入力値は以下の通り

  • input.pdf: 元のPDFファイル名
  • N: PDFのページ数
  • output.pdf: 出力する逆順にしたPDFファイル名

PDFサイズを圧縮する

さて、これで Send to Kindle by Email でさくっと送るぞと思ったら、Gmailの添付するファイルサイズの上限を超えていて「Google Driveのリンクをシェアしますか?」とか聞かれたので困った。見てみたらファイルサイズが50MBを超えている。

ちょっと調べてみたらGhostscriptを使ってPDFを簡単に圧縮できるようだったので試してみた。

$ gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dCompatibilityLevel=1.5 -dPDFSETTINGS=/ebook -sOutputFile=output.pdf input.pdf

ここで入力値は以下の通り

  • input.pdf: 先程逆順にしたPDFファイル名
  • output.pdf: 圧縮済みのPDFファイル名

また各種オプションはmanや公式ドキュメントを見てもらったほうが良いですが、メモとして残しておくと

  • -dBATCH と -dNOPAUSE: PDFファイルの各ページごとに停止して確認しながらループするのではなく、全ページ一気に処理するときに指定
  • -sDEVICE: 出力先デバイスの指定なんだけど、PDFファイルに書き込む場合はここで pdfwrite を指定
  • -dCompatibilityLevel: 圧縮する際のAdobe Distiller 5互換のパラメータ(ここの表参照)
  • -dPDFSETTINGS: Adobe Distillerに対するプリセットの設定群を適用できるラベル。電子書籍用であれば /ebook を指定するのが良いと思う。(/screen だと粗すぎると感じた)

処理結果

% ls -lh *.pdf
-rw-r--r-- 1 ymotongpoo users 20M  4月 14 19:23 reversed-compressed.pdf
-rw-r--r-- 1 ymotongpoo users 53M  4月 14 18:50 reversed.pdf
-rw-r--r-- 1 ymotongpoo users 53M  4月 14 18:47 original.pdf

53MBが20MBに圧縮されました!

参照

*1:自分が持っているのはKindle Paperwhite

OpenCensusでStackdriver Monitoringにメトリクスを送信する

はじめに

こんにちは、Stackdriver担当者です。先日Raspberry Pi Zero WにつけたBMP680から得たデータをStackdriver Monitoring API v3を使って送信してダッシュボードを作るという記事を書来ました。

ymotongpoo.hatenablog.com

しかしBMP680のデータを眺めていると結構精度が怪しいのでキャリブレーション用のデータが必要だなと思い、外気温のデータもStackdriver Monitoringに送ることにしました。それにOpenCensusを使ったのですが、GCPUG SlackでStackdriverに送るまとめをOpenCensus meetup vol.1までに公開すると言っていたのを忘れてたので慌てて記事にしました。

TL;DR

OpenWeatherMapとから外気の気温、湿度、大気圧、その他諸々のデータを取得し、OpenCensusを使ってStackdriver Monitoringにデータを送った。

OpenCensus Stats/Metrics

OpenCensusには大きく分けてTraceとStats/Metricsという2つの機能があり、それぞれStackdriver TraceとStackdriver Monitoringに対応したデータを送信できます。

OpenCensus Stats Exporter for Go

今回は OpenCensus Stats/Metrics の Stackdriver Exporter を使って Stackdriver Monitoring に送信するわけですが、Stackdriver Monitoring API v3を使っている用語と OpenCensus で使っている用語が違うので、公式ドキュメントにもある対応表をまず理解したほうが、いろいろなドキュメントが読みやすいです。

OpenCensus Stackdriver Monitoring 補足
Exporter N/A OpenCensusとモニタリングバックエンドをつなぐためのインターフェース
View MetricsDescriptor 記録するメトリクスのメタ情報
Measure MetricKind メトリクスのデータ型の定義
Aggregation ValueType メトリクス送信時の時系列データとしての扱い
Measurement Point ある一時点でのメトリクスの記録
View Data TimeSeries メトリクスの実データを送信前にバッファしておく入れ物
Tag LabelDescriptor ViewっやMeasureに対するラベル(OpenCensusではResourceとMetricに区別したラベルを付けない)

その上でサンプルコードを読むと大まかな雰囲気がわかります。

サンプルコードはPrometheus用のコードになっているので Exporter の部分だけ、Stackdriver Monitoring 用に置き換えてやる必要があります。といっても必要なのは Exporter の初期化の部分だけです。

type GenericNodeMonitoredResource struct {
    Location    string
    NamespaceId string
    NodeId      string
}

func NewGenericNodeMonitoredResource(location, namespace, node string) *GenericNodeMonitoredResource {
    return &GenericNodeMonitoredResource{
        Location:    location,
        NamespaceId: namespace,
        NodeId:      node,
    }
}

func (mr *GenericNodeMonitoredResource) MonitoredResource() (string, map[string]string) {
    labels := map[string]string{
        "location":  mr.Location,
        "namespace": mr.NamespaceId,
        "node_id":   mr.NodeId,
    }
    return "generic_node", labels
}

func GetMetricType(v *view.View) string {
    return fmt.Sprintf("custom.googleapis.com/%s", v.Name)
}

func InitExporter() *stackdriver.Exporter {
    mr := NewGenericNodeMonitoredResource(ResourceLocation, ResourceNamespace, "public-data")
    labels := &stackdriver.Labels{}
    exporter, err := stackdriver.NewExporter(stackdriver.Options{
        ProjectID:               os.Getenv("GOOGLE_CLOUD_PROJECT"),
        Location:                ResourceLocation,
        MonitoredResource:       mr,
        DefaultMonitoringLabels: labels,
        GetMetricType:           GetMetricType,
    })
    if err != nil {
        log.Fatal("failed to initialize ")
    }
    return exporter
}

Exporterの設定ではStackdriver特有の設定を行うところがポイントで、このGoDocをとりあえずガン見することになると思います。

godoc.org

ここのOptions構造体のドキュメントをよく読んでおけば設定ではまることはあまりないはずです。あるとすれば、 MonitoredResourceDefaultMonitoringLabels あたり。基本的にStackdriver Monitoring側で事前定義されているようなラベルは MonitoredResource で作るわけですが、ちょっとはまりどころとして、これが monitoredresource.Interface 型であるということ。Stackdriver用の事前定義の設定ではGKE、GCE、EC2ぐらいしか使わない前提で構造体がほとんど作られていないので(パッケージ参照)、その他のリソースに関しては上のように構造体を自前実装する必要があります。

DefaultMonitoringLabels はそれ以外で固定でつけるようなラベルを入れておくと良いです。ドキュメントにもありますが、ここを設定しないとデフォルトは opencensus_task というラベルで値にプロセス名が入ったものが勝手に送られてしまうので、そうしたくない場合は空の *stackdriver.Labels を設定すれば大丈夫です。

OpenCensus Stats

Exporterの設定は上記ぐらいなので、次にメトリクスを取得する部分であるViewの設定です。これはベストプラクティスとして、View、Measure、Key、といったものはすべてパッケージグローバルで設定しておくというのがあります。

const (
    // OCReportInterval is the interval for OpenCensus to send stats data to
    // Stackdriver Monitoring via its exporter.
    // NOTE: this value should not be no less than 1 minute. Detailes are in the doc.
    // https://cloud.google.com/monitoring/custom-metrics/creating-metrics#writing-ts
    OCReportInterval = 60 * time.Second

    // Measure namess for respecitive OpenCensus Measure
    MeasureTemperature = "temperature"
    MeasurePressure    = "pressure"
    MeasureHumidity    = "humidity"
    MeasureWindSpeed   = "windspeed"
    MeasureWindDeg     = "winddeg"

    // Units are used to define Measures of OpenCensus.
    TemperatureUnit = "C"
    PressureUnit    = "hPa"
    HumidityUnit    = "%"
    WindSpeedUnit   = "mps"
    WindDegUnit     = "degree"

    // ResouceNamespace is used for the exporter to have resource labels.
    ResourceNamespace = "ymotongpoo"
)

var (
    // Measure variables
    MTemperature = stats.Float64(MeasureTemperature, "air temperature", TemperatureUnit)
    MPressure    = stats.Float64(MeasurePressure, "barometric pressure", PressureUnit)
    MHumidity    = stats.Int64(MeasureHumidity, "air humidity", HumidityUnit)
    MWindSpeed   = stats.Float64(MeasureWindSpeed, "wind speed", WindSpeedUnit)
    MWindDeg     = stats.Float64(MeasureWindDeg, "wind degree from North", WindDegUnit)

    TemperatureView = &view.View{
        Name:        MeasureTemperature,
        Measure:     MTemperature,
        TagKeys:     []tag.Key{KeySource},
        Description: "air temperature",
        Aggregation: view.LastValue(),
    }

    PressureView = &view.View{
        Name:        MeasurePressure,
        Measure:     MPressure,
        TagKeys:     []tag.Key{KeySource},
        Description: "barometric pressure",
        Aggregation: view.LastValue(),
    }

    HumidityView = &view.View{
        Name:        MeasureHumidity,
        Measure:     MHumidity,
        TagKeys:     []tag.Key{KeySource},
        Description: "air humidity",
        Aggregation: view.LastValue(),
    }

    WindSpeedView = &view.View{
        Name:        MeasureWindSpeed,
        Measure:     MWindSpeed,
        TagKeys:     []tag.Key{KeySource},
        Description: "wind speed",
        Aggregation: view.LastValue(),
    }

    WeatherReportViews = []*view.View{
        TemperatureView,
        PressureView,
        HumidityView,
        WindSpeedView,
    }

    // KeySource is the key for label in "generic_node",
    KeySource, _ = tag.NewKey("source")
)

パッケージグローバルにとどまらず、そもそもこうした変数や定数だけを持ったパッケージを公開するのも良いでしょう。実際、アプリケーション内の複数のマイクロサービスで共通で使われるようなメトリクスなどは、そうしておくことでViewの初期化が簡単になります。たとえば gRPC 用の事前定義パッケージでは、よく使われるViewが事前定義されています。

これらと先程作成したExporterを使ってViewを初期化する手続きはたったこれだけです。

func InitOpenCensusStats(exporter *stackdriver.Exporter) {
    view.SetReportingPeriod(OCReportInterval)
    view.RegisterExporter(exporter)
    view.Register(WeatherReportViews...)
}

ここで一つだけ注意したいのがViewがStackdriverにレポートを送る間隔の設定(SetReportPeriod)です。これはOpenCensusのドキュメントやStackdriver MonitoringのAPIドキュメントにもあるように、1分以下に設定してしまうと「間隔が短い」と怒られます。

Note: each exporter makes different promises about what the lowest supported duration is. For example, the Stackdriver exporter recommends a value no lower than 1 minute. Consult each exporter per your needs.

Don't make the calls faster than one time per minute.

値を記録する

あとは値を記録するだけです。 stats.Record で Measurement を記録するだけです。記録さえしておけば、Viewがよしなに設定した間隔でStackdriver Monitoringにデータを送ってくれます。

func RecordMeasurement(id string, w *Weather) error {
    ctx, err := tag.New(context.Background(), tag.Upsert(KeySource, id))
    if err != nil {
        logger.Errorf("failed to insert key: %v", err)
        return err
    }

    stats.Record(ctx,
        MTemperature.M(w.Temperature),
        MPressure.M(w.Pressure),
        MHumidity.M(int64(w.Humidity)),
        MWindSpeed.M(w.WindSpeed),
    )
    return nil
}

コードも貼ったので長く見えますが、たったこれだけの手順で簡単にStackdriver MonitoringにOpenCensusを使ってデータを送れるようになります。

参照

OpenCensus + Stackdriver Monitoring

OpenWeatherMap API

Dark Sky API