Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial delivery of metrics code #81

Merged
merged 3 commits into from
May 24, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
downloads
test
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -40,7 +40,6 @@ install:

script:
- make deps
- make vet
- make build-devserver
- make build-devjmstest
- eval "$DOCKER_DOWNGRADE"
4 changes: 3 additions & 1 deletion Dockerfile-server
Original file line number Diff line number Diff line change
@@ -17,11 +17,12 @@ ARG BASE_IMAGE=ubuntu:16.04
###############################################################################
# Build stage to build Go code
###############################################################################
FROM golang:1.10 as builder
FROM mq-golang-sdk:9.0.5.0-x86_64-ubuntu-16.04 as builder
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
COPY cmd/ ./cmd
COPY internal/ ./internal
COPY vendor/ ./vendor
COPY test/ ./test
RUN go build ./cmd/runmqserver/
RUN go build ./cmd/chkmqready/
RUN go build ./cmd/chkmqhealthy/
@@ -30,6 +31,7 @@ RUN go test -v ./cmd/runmqserver/
RUN go test -v ./cmd/chkmqready/
RUN go test -v ./cmd/chkmqhealthy/
RUN go test -v ./internal/...
RUN go vet ./cmd/... ./internal/... ./test/...

###############################################################################
# Main build stage, to build MQ image
19 changes: 9 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
@@ -104,7 +104,7 @@ all: build-devserver build-advancedserver
test-all: test-devserver test-advancedserver

.PHONY: precommit
precommit: vet fmt lint all test-all
precommit: fmt lint all test-all

.PHONY: devserver
devserver: build-devserver test-devserver
@@ -142,7 +142,7 @@ build-cov:

# Shortcut to just run the unit tests
.PHONY: test-unit
test-unit:
test-unit: test/docker/vendor
docker build --target builder --file Dockerfile-server .

.PHONY: test-advancedserver
@@ -200,7 +200,6 @@ define docker-build-mq
nginx:alpine
# Build the new image (use --pull to make sure we have the latest base image)
$(DOCKER) build \
--pull \
--tag $1 \
--file $2 \
--network build \
@@ -221,14 +220,14 @@ docker-version:
@test "$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -ge "17" || ("$(word 1,$(subst ., ,$(DOCKER_SERVER_VERSION)))" -eq "17" && "$(word 2,$(subst ., ,$(DOCKER_CLIENT_VERSION)))" -ge "05") || (echo "Error: Docker server 17.05 or greater is required" && exit 1)

.PHONY: build-advancedserver
build-advancedserver: downloads/$(MQ_ARCHIVE) docker-version
build-advancedserver: downloads/$(MQ_ARCHIVE) docker-version build-golang-sdk test/docker/vendor
$(info $(SPACER)$(shell printf $(TITLE)"Build $(MQ_IMAGE_ADVANCEDSERVER)"$(END)))
$(call docker-build-mq,$(MQ_IMAGE_ADVANCEDSERVER),Dockerfile-server,$(MQ_ARCHIVE),"4486e8c4cc9146fd9b3ce1f14a2dfc5b","IBM MQ Advanced",$(MQ_VERSION))

.PHONY: build-devserver
# Target-specific variable to add web server into devserver image
build-devserver: MQ_PACKAGES=ibmmq-server ibmmq-java ibmmq-jre ibmmq-gskit ibmmq-msg-.* ibmmq-samples ibmmq-ams ibmmq-web
build-devserver: downloads/$(MQ_ARCHIVE_DEV) docker-version
build-devserver: downloads/$(MQ_ARCHIVE_DEV) docker-version build-golang-sdk test/docker/vendor
@test "$(shell uname -m)" = "x86_64" || (echo "Error: MQ Advanced for Developers is only available for x86_64 architecture" && exit 1)
$(info $(shell printf $(TITLE)"Build $(MQ_IMAGE_DEVSERVER_BASE)"$(END)))
$(call docker-build-mq,$(MQ_IMAGE_DEVSERVER_BASE),Dockerfile-server,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))
@@ -238,25 +237,25 @@ build-devserver: downloads/$(MQ_ARCHIVE_DEV) docker-version
build-advancedserver-cover: docker-version
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_ADVANCEDSERVER) -t $(MQ_IMAGE_ADVANCEDSERVER)-cover -f Dockerfile-server.cover .

.PHONY: build-explorer
.PHONY: build-explorer docker-pull
build-explorer: downloads/$(MQ_ARCHIVE_DEV)
$(call docker-build-mq,mq-explorer:latest-$(ARCH),incubating/mq-explorer/Dockerfile-mq-explorer,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers (Non-Warranted)",$(MQ_VERSION))

build-sdk: downloads/$(MQ_ARCHIVE) docker-version
build-sdk: downloads/$(MQ_ARCHIVE_DEV) docker-version docker-pull
$(call docker-build-mq,$(MQ_IMAGE_SDK),incubating/mq-sdk/Dockerfile,$(MQ_ARCHIVE_DEV),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers SDK (Non-Warranted)",$(MQ_VERSION))

build-golang-sdk: build-sdk
$(DOCKER) build --build-arg BASE_IMAGE=$(MQ_IMAGE_SDK) -t $(MQ_IMAGE_GOLANG_SDK) -f incubating/mq-golang-sdk/Dockerfile .
# $(call docker-build-mq,$(MQ_IMAGE_GOLANG_SDK),incubating/mq-golang-sdk/Dockerfile,$(MQ_ARCHIVE),"98102d16795c4263ad9ca075190a2d4d","IBM MQ Advanced for Developers SDK (Non-Warranted)",$(MQ_VERSION))

docker-pull:
$(DOCKER) pull $(BASE_IMAGE)

GO_PKG_DIRS = ./cmd ./internal ./test

fmt: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
go fmt $(addsuffix /..., $(GO_PKG_DIRS))

vet: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS)) test/docker/vendor
go vet $(addsuffix /..., $(GO_PKG_DIRS))

lint: $(addsuffix /$(wildcard *.go), $(GO_PKG_DIRS))
@# This expression is necessary because /... includes the vendor directory in golint
@# As of 11/04/2018 there is an open issue to fix it: https://github.com/golang/lint/issues/320
9 changes: 9 additions & 0 deletions cmd/runmqserver/main.go
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ import (
"os"
"sync"

"github.com/ibm-messaging/mq-container/internal/metrics"
"github.com/ibm-messaging/mq-container/internal/name"
"github.com/ibm-messaging/mq-container/internal/ready"
)
@@ -117,6 +118,14 @@ func doMain() error {
return err
}
configureQueueManager()

enableMetrics := os.Getenv("MQ_ENABLE_METRICS")
if enableMetrics == "true" || enableMetrics == "1" {
go metrics.GatherMetrics(name, log)
} else {
log.Println("Metrics are disabled")
}

// Start reaping zombies from now on.
// Start this here, so that we don't reap any sub-processes created
// by this process (e.g. for crtmqm or strmqm)
80 changes: 39 additions & 41 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
@@ -20,3 +20,6 @@ excludeDirs:
- test
import:
- package: golang.org/x/sys/unix
- package: github.com/prometheus/client_golang
- package: github.com/ibm-messaging/mq-golang
version: dev
2 changes: 1 addition & 1 deletion incubating/mqadvanced-server-dev/Dockerfile
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
###############################################################################
# Build stage to build Go code
###############################################################################
FROM golang:1.10 as builder
FROM mq-golang-sdk:9.0.5.0-x86_64-ubuntu-16.04 as builder
WORKDIR /go/src/github.com/ibm-messaging/mq-container/
COPY cmd/ ./cmd
COPY internal/ ./internal
107 changes: 107 additions & 0 deletions internal/metrics/exporter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
© Copyright IBM Corporation 2018

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package metrics contains code to provide metrics for the queue manager
package metrics

import (
"github.com/prometheus/client_golang/prometheus"
)

const (
namespace = "ibmmq"
qmgrPrefix = "qmgr"
qmgrLabel = "qmgr"
objectPrefix = "object"
objectLabel = "object"
)

type exporter struct {
qmName string
gaugeMap map[string]*prometheus.GaugeVec
}

func newExporter(qmName string) *exporter {
return &exporter{
qmName: qmName,
gaugeMap: make(map[string]*prometheus.GaugeVec),
}
}

// Describe provides details of all available metrics
func (e *exporter) Describe(ch chan<- *prometheus.Desc) {

requestChannel <- false
response := <-responseChannel

for key, metric := range response {

// Allocate a Prometheus Gauge for each available metric
gaugeVec := createGaugeVec(metric.name, metric.description, metric.objectType)
e.gaugeMap[key] = gaugeVec

// Describe metric
gaugeVec.Describe(ch)
}
}

// Collect is called at regular intervals to provide the current metric data
func (e *exporter) Collect(ch chan<- prometheus.Metric) {

requestChannel <- true
response := <-responseChannel

for key, metric := range response {

// Reset Prometheus Gauge
gaugeVec := e.gaugeMap[key]
gaugeVec.Reset()

// Populate Prometheus Gauge with metric values
for label, value := range metric.values {
if label == qmgrLabelValue {
gaugeVec.WithLabelValues(e.qmName).Set(value)
} else {
gaugeVec.WithLabelValues(label, e.qmName).Set(value)
}
}

// Collect metric
gaugeVec.Collect(ch)
}
}

// createGaugeVec returns a Prometheus GaugeVec populated with metric details
func createGaugeVec(name, description string, objectType bool) *prometheus.GaugeVec {

prefix := qmgrPrefix
labels := []string{qmgrLabel}

if objectType {
prefix = objectPrefix
labels = []string{objectLabel, qmgrLabel}
}

gaugeVec := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: namespace,
Name: prefix + "_" + name,
Help: description,
},
labels,
)
return gaugeVec
}
54 changes: 54 additions & 0 deletions internal/metrics/exporter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
© Copyright IBM Corporation 2018

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package metrics

import (
"testing"

"github.com/prometheus/client_golang/prometheus"
)

func TestCreateGaugeVec(t *testing.T) {

ch := make(chan *prometheus.Desc)
gaugeVec := createGaugeVec("MetricName", "MetricDescription", false)
go func() {
gaugeVec.Describe(ch)
}()
description := <-ch

expected := "Desc{fqName: \"ibmmq_qmgr_MetricName\", help: \"MetricDescription\", constLabels: {}, variableLabels: [qmgr]}"
actual := description.String()
if actual != expected {
t.Errorf("Expected value=%s; actual %s", expected, actual)
}
}

func TestCreateGaugeVec_ObjectLabel(t *testing.T) {

ch := make(chan *prometheus.Desc)
gaugeVec := createGaugeVec("MetricName", "MetricDescription", true)
go func() {
gaugeVec.Describe(ch)
}()
description := <-ch

expected := "Desc{fqName: \"ibmmq_object_MetricName\", help: \"MetricDescription\", constLabels: {}, variableLabels: [object qmgr]}"
actual := description.String()
if actual != expected {
t.Errorf("Expected value=%s; actual %s", expected, actual)
}
}
97 changes: 97 additions & 0 deletions internal/metrics/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package metrics contains code to provide metrics for the queue manager
package metrics

import (
"fmt"
"net/http"
"time"

"github.com/ibm-messaging/mq-container/internal/logger"
"github.com/ibm-messaging/mq-golang/mqmetric"
"github.com/prometheus/client_golang/prometheus"
)

const (
defaultPort = "9157"
retryCount = 3
retryWait = 5
)

// GatherMetrics gathers metrics for the queue manager
func GatherMetrics(qmName string, log *logger.Logger) {

for i := 0; i <= retryCount; i++ {
err := startMetricsGathering(qmName, log)
if err != nil {
log.Errorf("Metrics Error: %s", err.Error())
}
if i != retryCount {
log.Printf("Waiting %d seconds before retrying metrics gathering", retryWait)
time.Sleep(retryWait * time.Second)
} else {
log.Println("Unable to gather metrics - metrics are now disabled")
}
}
}

// startMetricsGathering starts gathering metrics for the queue manager
func startMetricsGathering(qmName string, log *logger.Logger) error {

defer func() {
if r := recover(); r != nil {
log.Errorf("Metrics Error: %v", r)
}
}()

log.Println("Starting metrics gathering")

// Set connection configuration
var connConfig mqmetric.ConnectionConfig
connConfig.ClientMode = false
connConfig.UserId = ""
connConfig.Password = ""

// Connect to the queue manager - open the command and dynamic reply queues
err := mqmetric.InitConnectionStats(qmName, "SYSTEM.DEFAULT.MODEL.QUEUE", "", &connConfig)
if err != nil {
return fmt.Errorf("Failed to connect to queue manager %s: %v", qmName, err)
}
defer mqmetric.EndConnection()

// Discover available metrics for the queue manager and subscribe to them
err = mqmetric.DiscoverAndSubscribe("", true, "")
if err != nil {
return fmt.Errorf("Failed to discover and subscribe to metrics: %v", err)
}

// Start processing metrics
go processMetrics(log)

// Register metrics
prometheus.MustRegister(newExporter(qmName))

// Setup HTTP server to handle requests from Prometheus
http.Handle("/metrics", prometheus.Handler())
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Write([]byte("Status: METRICS ACTIVE"))
})
err = http.ListenAndServe(":"+defaultPort, nil)
return fmt.Errorf("Failed to handle metrics request: %v", err)
}
119 changes: 119 additions & 0 deletions internal/metrics/update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package metrics contains code to provide metrics for the queue manager
package metrics

import (
"strings"
"time"

"github.com/ibm-messaging/mq-container/internal/logger"
"github.com/ibm-messaging/mq-golang/mqmetric"
)

const (
qmgrLabelValue = mqmetric.QMgrMapKey
requestTimeout = 10
)

var (
requestChannel = make(chan bool)
responseChannel = make(chan map[string]*metricData)
)

type metricData struct {
name string
description string
objectType bool
values map[string]float64
}

// processMetrics processes publications of metric data and handles describe/collect requests
func processMetrics(log *logger.Logger) {

// Initialise metrics
metrics := initialiseMetrics()

for {
// Process publications of metric data
mqmetric.ProcessPublications()

// Handle describe/collect requests
select {
case collect := <-requestChannel:
if collect {
updateMetrics(metrics)
}
responseChannel <- metrics
case <-time.After(requestTimeout * time.Second):
log.Debugf("Metrics: No requests received within timeout period (%d seconds)", requestTimeout)
}
}
}

// initialiseMetrics sets initial details for all available metrics
func initialiseMetrics() map[string]*metricData {

metrics := make(map[string]*metricData)

for _, metricClass := range mqmetric.Metrics.Classes {
for _, metricType := range metricClass.Types {
if !strings.Contains(metricType.ObjectTopic, "%s") {
for _, metricElement := range metricType.Elements {
metric := metricData{
name: metricElement.MetricName,
description: metricElement.Description,
}
key := makeKey(metricElement)
metrics[key] = &metric
}
}
}
}
return metrics
}

// updateMetrics updates values for all available metrics
func updateMetrics(metrics map[string]*metricData) {

for _, metricClass := range mqmetric.Metrics.Classes {
for _, metricType := range metricClass.Types {
if !strings.Contains(metricType.ObjectTopic, "%s") {
for _, metricElement := range metricType.Elements {

// Clear existing metric values
metric := metrics[makeKey(metricElement)]
metric.values = make(map[string]float64)

// Update metric with cached values of publication data
for label, value := range metricElement.Values {
normalisedValue := mqmetric.Normalise(metricElement, label, value)
metric.values[label] = normalisedValue
}

// Reset cached values of publication data for this metric
metricElement.Values = make(map[string]int64)
}
}
}
}
}

// makeKey builds a unique key for each metric
func makeKey(metricElement *mqmetric.MonElement) string {
return metricElement.Parent.Parent.Name + "/" + metricElement.Parent.Name + "/" + metricElement.MetricName
}
112 changes: 112 additions & 0 deletions internal/metrics/update_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
© Copyright IBM Corporation 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package metrics

import (
"testing"

"github.com/ibm-messaging/mq-golang/mqmetric"
)

func TestInitialiseMetrics(t *testing.T) {

teardownTestCase := setupTestCase()
defer teardownTestCase()

metrics := initialiseMetrics()
metric, ok := metrics["ClassName/Type1Name/Element1Name"]

if !ok {
t.Error("Expected metric not found in map")
} else {
if metric.name != "Element1Name" {
t.Errorf("Expected name=%s; actual %s", "Element1Name", metric.name)
}
if metric.description != "Element1Description" {
t.Errorf("Expected description=%s; actual %s", "Element1Description", metric.description)
}
if metric.objectType != false {
t.Errorf("Expected objectType=%v; actual %v", false, metric.objectType)
}
if len(metric.values) != 0 {
t.Errorf("Expected values-size=%d; actual %d", 0, len(metric.values))
}
}
_, ok = metrics["ClassName/Type2Name/Element2Name"]
if ok {
t.Errorf("Unexpected metric found in map, %%s object topics should be ignored")
}

if len(metrics) != 1 {
t.Errorf("Map contains unexpected metrics, map size=%d", len(metrics))
}
}

func TestMakeKey(t *testing.T) {

teardownTestCase := setupTestCase()
defer teardownTestCase()

expected := "ClassName/Type1Name/Element1Name"
actual := makeKey(mqmetric.Metrics.Classes[0].Types[0].Elements[0])
if actual != expected {
t.Errorf("Expected value=%s; actual %s", expected, actual)
}
}

func setupTestCase() func() {
populateTestMetrics()
return func() {
cleanTestMetrics()
}
}

func populateTestMetrics() {

metricClass := new(mqmetric.MonClass)
metricType1 := new(mqmetric.MonType)
metricType2 := new(mqmetric.MonType)
metricElement1 := new(mqmetric.MonElement)
metricElement2 := new(mqmetric.MonElement)

metricClass.Name = "ClassName"
metricType1.Name = "Type1Name"
metricType2.Name = "Type2Name"
metricElement1.MetricName = "Element1Name"
metricElement1.Description = "Element1Description"
metricElement2.MetricName = "Element2Name"
metricElement2.Description = "Element2Description"
metricType1.ObjectTopic = "ObjectTopic"
metricType2.ObjectTopic = "%s"
metricElement1.Parent = metricType1
metricElement2.Parent = metricType2
metricType1.Parent = metricClass
metricType2.Parent = metricClass

metricType1.Elements = make(map[int]*mqmetric.MonElement)
metricType2.Elements = make(map[int]*mqmetric.MonElement)
metricType1.Elements[0] = metricElement1
metricType2.Elements[0] = metricElement2
metricClass.Types = make(map[int]*mqmetric.MonType)
metricClass.Types[0] = metricType1
metricClass.Types[1] = metricType2
mqmetric.Metrics.Classes = make(map[int]*mqmetric.MonClass)
mqmetric.Metrics.Classes[0] = metricClass
}

func cleanTestMetrics() {
mqmetric.Metrics.Classes = make(map[int]*mqmetric.MonClass)
}
2 changes: 2 additions & 0 deletions vendor/github.com/beorn7/perks/.gitignore
20 changes: 20 additions & 0 deletions vendor/github.com/beorn7/perks/LICENSE
31 changes: 31 additions & 0 deletions vendor/github.com/beorn7/perks/README.md
26 changes: 26 additions & 0 deletions vendor/github.com/beorn7/perks/histogram/bench_test.go
108 changes: 108 additions & 0 deletions vendor/github.com/beorn7/perks/histogram/histogram.go
38 changes: 38 additions & 0 deletions vendor/github.com/beorn7/perks/histogram/histogram_test.go
63 changes: 63 additions & 0 deletions vendor/github.com/beorn7/perks/quantile/bench_test.go
121 changes: 121 additions & 0 deletions vendor/github.com/beorn7/perks/quantile/example_test.go
2,388 changes: 2,388 additions & 0 deletions vendor/github.com/beorn7/perks/quantile/exampledata.txt

Large diffs are not rendered by default.

316 changes: 316 additions & 0 deletions vendor/github.com/beorn7/perks/quantile/stream.go
215 changes: 215 additions & 0 deletions vendor/github.com/beorn7/perks/quantile/stream_test.go
90 changes: 90 additions & 0 deletions vendor/github.com/beorn7/perks/topk/topk.go
57 changes: 57 additions & 0 deletions vendor/github.com/beorn7/perks/topk/topk_test.go
16 changes: 16 additions & 0 deletions vendor/github.com/golang/protobuf/.gitignore
40 changes: 40 additions & 0 deletions vendor/github.com/golang/protobuf/Make.protobuf
55 changes: 55 additions & 0 deletions vendor/github.com/golang/protobuf/Makefile
241 changes: 241 additions & 0 deletions vendor/github.com/golang/protobuf/README.md
33 changes: 33 additions & 0 deletions vendor/github.com/golang/protobuf/_conformance/Makefile
161 changes: 161 additions & 0 deletions vendor/github.com/golang/protobuf/_conformance/conformance.go

Large diffs are not rendered by default.

829 changes: 829 additions & 0 deletions vendor/github.com/golang/protobuf/jsonpb/jsonpb.go

Large diffs are not rendered by default.

561 changes: 561 additions & 0 deletions vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go

Large diffs are not rendered by default.

Large diffs are not rendered by default.

43 changes: 43 additions & 0 deletions vendor/github.com/golang/protobuf/proto/Makefile
Loading