Go 1.13時点では、モジュール管理しているリポジトリでgoimportsなどのツールをgo getすると、go.modが書き換えられて管理対象に入ります*1が、恒久的にソースコードへ含まれる訳ではないため、go mod tidyなどで整理すると、ツールのインストール時に追加されたモジュールがgo.modから削除されます。ここではツールもバージョン管理したいので、ビルド制約(build constraints)でビルド対象に含まれないようにしたファイルに、利用するツールを書き並べていきます。このときのビルドタグやファイル名はなんでも構いませんが、公式ではファイル名にtools.go、ビルドタグにtoolsが使われているので、合わせておいくといいでしょう。
// バージョン確認
% go list -m-u all
// 以下のうちどれかでアップデート
% go get golang.org/x/lint/golint
% go get -u golang.org/x/lint/golint
% go get -u=patch golang.org/x/lint/golint
% git add go.mod go.sum
go getの使い分け
Goモジュールではgo getだけでgo.modに関わらず最新のバージョンを取得するので、go get -uとの違いについてGOPATHモードのgo getを知っている人は混乱するかもしれません。これはgo help module-getによると、インストールするモジュールが依存するモジュールをどう扱うか、を表すようです。
go get <pkg>: <pkg>のgo.modに書かれたバージョンをminimal version selectionで維持する
go get -u <pkg>: <pkg>が依存するモジュールも同じメジャーバージョン内でアップデートする
go get -u=patch <pkg>: <pkg>が依存するモジュールも同じマイナーバージョン内でアップデートする
% go version
go version go1.13.5 darwin/amd64
% go get github.com/github/hub@v2.14.1
go: finding github.com/github/hub v2.14.1
go: finding github.com/github/hub v2.14.1
go get github.com/github/hub@v2.14.1: github.com/github/hub@v2.14.1: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2
for _, a := range requests { // 500件ごとに分割してある
b := c.Batch()
for _, p := range a {
b.Create(c.Doc(p.Key), p)
}
if err := b.Commit(); err != nil {
return err
}
}
e, err := exporter.NewExporter(exporter.Options{
})
if err != nil {
log.Fatal(err)
}
if err := e.Start(1 * time.Minute); err != nil {
log.Fatal(err)
}
defer e.Stop()
Exporter自体の実装。
// Exporter is a stats exporter that uploads data to Mackerel.type Exporter struct {
opts Options
once sync.Once
r *metricexport.IntervalReader
c *mackerel.Client
}
// Options contains options for configuring the exporter.type Options struct {
APIKey string
}
func NewExporter(o Options) (*Exporter, error) {
c := mackerel.NewClient(o.APIKey)
return &Exporter{
opts: o,
c: c,
}, nil
}
// Start starts the metric exporter.func (e *Exporter) Start(interval time.Duration) error {
var err error
e.once.Do(func() {
e.r, err = metricexport.NewIntervalReader(&metricexport.Reader{}, e)
})
if err != nil {
return err
}
//trace.RegisterExporter(e)
e.r.ReportingInterval = interval
return e.r.Start()
}
func (e *Exporter) Stop() {
//trace.UnregisterExporter(e)
e.r.Stop()
}
func (e *Exporter) ExportMetrics(ctx context.Context, data []*metricdata.Metric) error {
a := convertToHostMetrics(data)
if err := e.c.PostHostMetricValues(a); err != nil {
e.ErrLog(err)
return err
}
returnnil
}
func convertToHostMetrics(a []*metricdata.Metric) []*mackerel.HostMetricValue {
var r []*mackerel.HostMetricValue
for _, p := range a {
// View.Nameの値から'/'を'.'に置き換え
name := metricName(p.Descriptor)
// 値と一緒に記録したタグからホストIDを取り出す
i := labelKeyIndex(p.Descriptor, HostKeyID.Name())
if i < 0 {
continue
}
for _, ts := range p.TimeSeries {
if !ts.LabelValues[i].Present {
continue
}
hostID := ts.LabelValues[i].Value
// OpenCensusのMetricをMackerelのホストメトリックに変換
a := hostMetricValues(hostID, metricValues(name, ts.Points))
r = append(r, a...)
}
}
return r
}
func labelKeyIndex(d metricdata.Descriptor, key string) int {
for i, k := range d.LabelKeys {
if k.Key == key {
return i
}
}
return -1
}
func hostMetricValues(...省略...)