<commit_before>// Copyright 2016 The nvim-go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package command

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/neovim/go-client/nvim"
	"github.com/pkg/errors"
	"github.com/zchee/nvim-go/src/config"
	"github.com/zchee/nvim-go/src/logger"
	"github.com/zchee/nvim-go/src/nvimutil"
	"github.com/zchee/nvim-go/src/pathutil"
	"go.uber.org/zap"
)

// CmdBuildEval struct type for Eval of GoBuild command.
type CmdBuildEval struct {
	Cwd  string `msgpack:",array"`
	File string
}

func (c *Command) cmdBuild(args []string, bang bool, eval *CmdBuildEval) {
	go func() {
		c.errs.Delete("Build")

		err := c.Build(args, bang, eval)
		switch e := err.(type) {
		case error:
			nvimutil.ErrorWrap(c.Nvim, e)
		case []*nvim.QuickfixError:
			c.errs.Store("Build", e)
			errlist := make(map[string][]*nvim.QuickfixError)
			c.errs.Range(func(ki, vi interface{}) bool {
				k, v := ki.(string), vi.([]*nvim.QuickfixError)
				errlist[k] = append(errlist[k], v...)
				return true
			})
			nvimutil.ErrorList(c.Nvim, errlist, true)
		}
	}()
}

// Build builds the current buffers package use compile tool that determined
// from the package directory structure.
func (c *Command) Build(args []string, bang bool, eval *CmdBuildEval) interface{} {
	if !bang {
		bang = config.BuildForce
	}
	wd := filepath.Dir(eval.File)
	if len(args) >= 1 {
		wd = eval.Cwd
	}

	cmd, err := c.compileCmd(args, bang, wd)
	if err != nil {
		return errors.WithStack(err)
	}
	var stderr bytes.Buffer
	cmd.Stderr = &stderr

	if buildErr := cmd.Run(); buildErr != nil {
		if err, ok := buildErr.(*exec.ExitError); ok && err != nil {
			errlist, err := nvimutil.ParseError(stderr.Bytes(), eval.Cwd, &c.buildContext.Build, nil)
			if err != nil {
				return errors.WithStack(err)
			}
			return errlist
		}
		return errors.WithStack(buildErr)
	}

	return nvimutil.EchoSuccess(c.Nvim, "GoBuild", fmt.Sprintf("compiler: %s", c.buildContext.Build.Tool))
}

// compileCmd returns the *exec.Cmd corresponding to the compile tool.
func (c *Command) compileCmd(args []string, bang bool, dir string) (*exec.Cmd, error) {
	bin, err := exec.LookPath(c.buildContext.Build.Tool)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	cmd := exec.Command(bin, "build")

	if len(config.BuildFlags) > 0 {
		args = append(args, config.BuildFlags...)
	}
	switch c.buildContext.Build.Tool {
	case "go":
		cmd.Dir = dir

		// Outputs the binary to DevNull if without bang
		if !bang || !matchSlice("-o", args) {
			args = append(args, "-o", os.DevNull)
		}
		// add "app" suffix to binary name if enable app-engine build
		if config.BuildAppengine {
			cmd.Args[0] += "app"
		}
	case "gb":
		cmd.Dir = c.buildContext.Build.ProjectRoot

		if config.BuildAppengine {
			cmd.Args = append([]string{cmd.Args[0], "gae"}, cmd.Args[1:]...)
			pkgs, err := pathutil.GbPackages(cmd.Dir)
			if err != nil {
				return nil, err
			}
			for _, pkg := range pkgs {
				// "gb gae build" doesn't compatible "gb build" arg. actually, "goapp build ..."
				cmd.Args = append(cmd.Args, pkg+string(filepath.Separator)+"...")
			}
		}
	}

	cmd.Args = append(cmd.Args, args...)
	logger.FromContext(c.ctx).Info("compileCmd", zap.Any("cmd", cmd))

	return cmd, nil
}

func matchSlice(s string, ss []string) bool {
	for _, str := range ss {
		if s == str {
			return true
		}
	}
	return false
}
<commit_msg>command/build: change pass compileCmd arg to eval.Cwd and append './...'<commit_after>// Copyright 2016 The nvim-go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package command

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/neovim/go-client/nvim"
	"github.com/pkg/errors"
	"github.com/zchee/nvim-go/src/config"
	"github.com/zchee/nvim-go/src/logger"
	"github.com/zchee/nvim-go/src/nvimutil"
	"github.com/zchee/nvim-go/src/pathutil"
	"go.uber.org/zap"
)

// CmdBuildEval struct type for Eval of GoBuild command.
type CmdBuildEval struct {
	Cwd  string `msgpack:",array"`
	File string
}

func (c *Command) cmdBuild(args []string, bang bool, eval *CmdBuildEval) {
	go func() {
		c.errs.Delete("Build")

		err := c.Build(args, bang, eval)
		switch e := err.(type) {
		case error:
			nvimutil.ErrorWrap(c.Nvim, e)
		case []*nvim.QuickfixError:
			c.errs.Store("Build", e)
			errlist := make(map[string][]*nvim.QuickfixError)
			c.errs.Range(func(ki, vi interface{}) bool {
				k, v := ki.(string), vi.([]*nvim.QuickfixError)
				errlist[k] = append(errlist[k], v...)
				return true
			})
			nvimutil.ErrorList(c.Nvim, errlist, true)
		}
	}()
}

// Build builds the current buffers package use compile tool that determined
// from the package directory structure.
func (c *Command) Build(args []string, bang bool, eval *CmdBuildEval) interface{} {
	log := logger.FromContext(c.ctx).With(zap.Strings("args", args), zap.Bool("bang", bang), zap.Any("CmdBuildEval", eval))
	if !bang {
		bang = config.BuildForce
	}

	cmd, err := c.compileCmd(args, bang, eval.Cwd)
	if err != nil {
		return errors.WithStack(err)
	}
	var stderr bytes.Buffer
	cmd.Stderr = &stderr

	log.Info("", zap.Any("cmd", cmd))

	if buildErr := cmd.Run(); buildErr != nil {
		if err, ok := buildErr.(*exec.ExitError); ok && err != nil {
			errlist, err := nvimutil.ParseError(stderr.Bytes(), eval.Cwd, &c.buildContext.Build, nil)
			if err != nil {
				return errors.WithStack(err)
			}
			return errlist
		}
		return errors.WithStack(buildErr)
	}

	return nvimutil.EchoSuccess(c.Nvim, "GoBuild", fmt.Sprintf("compiler: %s", c.buildContext.Build.Tool))
}

// compileCmd returns the *exec.Cmd corresponding to the compile tool.
func (c *Command) compileCmd(args []string, bang bool, dir string) (*exec.Cmd, error) {
	bin, err := exec.LookPath(c.buildContext.Build.Tool)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	cmd := exec.Command(bin, "build")

	if len(config.BuildFlags) > 0 {
		args = append(args, config.BuildFlags...)
	}
	switch c.buildContext.Build.Tool {
	case "go":
		cmd.Dir = dir

		// Outputs the binary to DevNull if without bang
		if !bang || !matchSlice("-o", args) {
			args = append(args, "-o", os.DevNull)
		}
		// add "app" suffix to binary name if enable app-engine build
		if config.BuildAppengine {
			cmd.Args[0] += "app"
		}
	case "gb":
		cmd.Dir = c.buildContext.Build.ProjectRoot

		if config.BuildAppengine {
			cmd.Args = append([]string{cmd.Args[0], "gae"}, cmd.Args[1:]...)
			pkgs, err := pathutil.GbPackages(cmd.Dir)
			if err != nil {
				return nil, err
			}
			for _, pkg := range pkgs {
				// "gb gae build" doesn't compatible "gb build" arg. actually, "goapp build ..."
				cmd.Args = append(cmd.Args, pkg+string(filepath.Separator)+"...")
			}
		}
	}

	args = append(args, "./...")
	cmd.Args = append(cmd.Args, args...)
	logger.FromContext(c.ctx).Info("compileCmd", zap.Any("cmd", cmd))

	return cmd, nil
}

func matchSlice(s string, ss []string) bool {
	for _, str := range ss {
		if s == str {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package executor

import (
	"context"
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"github.com/sirupsen/logrus"
	null "gopkg.in/guregu/null.v3"

	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/types"
	"github.com/loadimpact/k6/stats"
	"github.com/loadimpact/k6/ui/pb"
)

const perVUIterationsType = "per-vu-iterations"

func init() {
	lib.RegisterExecutorConfigType(perVUIterationsType, func(name string, rawJSON []byte) (lib.ExecutorConfig, error) {
		config := NewPerVUIterationsConfig(name)
		err := lib.StrictJSONUnmarshal(rawJSON, &config)
		return config, err
	})
}

// PerVUIterationsConfig stores the number of VUs iterations, as well as maxDuration settings
type PerVUIterationsConfig struct {
	BaseConfig
	VUs         null.Int           `json:"vus"`
	Iterations  null.Int           `json:"iterations"`
	MaxDuration types.NullDuration `json:"maxDuration"`
}

// NewPerVUIterationsConfig returns a PerVUIterationsConfig with default values
func NewPerVUIterationsConfig(name string) PerVUIterationsConfig {
	return PerVUIterationsConfig{
		BaseConfig:  NewBaseConfig(name, perVUIterationsType),
		VUs:         null.NewInt(1, false),
		Iterations:  null.NewInt(1, false),
		MaxDuration: types.NewNullDuration(10*time.Minute, false), //TODO: shorten?
	}
}

// Make sure we implement the lib.ExecutorConfig interface
var _ lib.ExecutorConfig = &PerVUIterationsConfig{}

// GetVUs returns the scaled VUs for the executor.
func (pvic PerVUIterationsConfig) GetVUs(et *lib.ExecutionTuple) int64 {
	return et.ES.Scale(pvic.VUs.Int64)
}

// GetIterations returns the UNSCALED iteration count for the executor. It's
// important to note that scaling per-VU iteration executor affects only the
// number of VUs. If we also scaled the iterations, scaling would have quadratic
// effects instead of just linear.
func (pvic PerVUIterationsConfig) GetIterations() int64 {
	return pvic.Iterations.Int64
}

// GetDescription returns a human-readable description of the executor options
func (pvic PerVUIterationsConfig) GetDescription(et *lib.ExecutionTuple) string {
	return fmt.Sprintf("%d iterations for each of %d VUs%s",
		pvic.GetIterations(), pvic.GetVUs(et),
		pvic.getBaseInfo(fmt.Sprintf("maxDuration: %s", pvic.MaxDuration.Duration)))
}

// Validate makes sure all options are configured and valid
func (pvic PerVUIterationsConfig) Validate() []error {
	errors := pvic.BaseConfig.Validate()
	if pvic.VUs.Int64 <= 0 {
		errors = append(errors, fmt.Errorf("the number of VUs should be more than 0"))
	}

	if pvic.Iterations.Int64 <= 0 {
		errors = append(errors, fmt.Errorf("the number of iterations should be more than 0"))
	}

	if time.Duration(pvic.MaxDuration.Duration) < minDuration {
		errors = append(errors, fmt.Errorf(
			"the maxDuration should be at least %s, but is %s", minDuration, pvic.MaxDuration,
		))
	}

	return errors
}

// GetExecutionRequirements returns the number of required VUs to run the
// executor for its whole duration (disregarding any startTime), including the
// maximum waiting time for any iterations to gracefully stop. This is used by
// the execution scheduler in its VU reservation calculations, so it knows how
// many VUs to pre-initialize.
func (pvic PerVUIterationsConfig) GetExecutionRequirements(et *lib.ExecutionTuple) []lib.ExecutionStep {
	return []lib.ExecutionStep{
		{
			TimeOffset: 0,
			PlannedVUs: uint64(pvic.GetVUs(et)),
		},
		{
			TimeOffset: time.Duration(pvic.MaxDuration.Duration + pvic.GracefulStop.Duration),
			PlannedVUs: 0,
		},
	}
}

// NewExecutor creates a new PerVUIterations executor
func (pvic PerVUIterationsConfig) NewExecutor(
	es *lib.ExecutionState, logger *logrus.Entry,
) (lib.Executor, error) {
	return PerVUIterations{
		BaseExecutor: NewBaseExecutor(pvic, es, logger),
		config:       pvic,
	}, nil
}

// HasWork reports whether there is any work to be done for the given execution segment.
func (pvic PerVUIterationsConfig) HasWork(et *lib.ExecutionTuple) bool {
	return pvic.GetVUs(et) > 0 && pvic.GetIterations() > 0
}

// PerVUIterations executes a specific number of iterations with each VU.
type PerVUIterations struct {
	*BaseExecutor
	config PerVUIterationsConfig
}

// Make sure we implement the lib.Executor interface.
var _ lib.Executor = &PerVUIterations{}

// Run executes a specific number of iterations with each configured VU.
func (pvi PerVUIterations) Run(ctx context.Context, out chan<- stats.SampleContainer) (err error) {
	numVUs := pvi.config.GetVUs(pvi.executionState.ExecutionTuple)
	iterations := pvi.config.GetIterations()
	duration := time.Duration(pvi.config.MaxDuration.Duration)
	gracefulStop := pvi.config.GetGracefulStop()

	startTime, maxDurationCtx, regDurationCtx, cancel := getDurationContexts(ctx, duration, gracefulStop)
	defer cancel()

	// Make sure the log and the progress bar have accurate information
	pvi.logger.WithFields(logrus.Fields{
		"vus": numVUs, "iterations": iterations, "maxDuration": duration, "type": pvi.config.GetType(),
	}).Debug("Starting executor run...")

	totalIters := uint64(numVUs * iterations)
	doneIters := new(uint64)

	vusFmt := pb.GetFixedLengthIntFormat(numVUs)
	itersFmt := pb.GetFixedLengthIntFormat(int64(totalIters))
	progresFn := func() (float64, []string) {
		spent := time.Since(startTime)
		progVUs := fmt.Sprintf(vusFmt+" VUs", numVUs)
		currentDoneIters := atomic.LoadUint64(doneIters)
		progIters := fmt.Sprintf(itersFmt+"/"+itersFmt+" iters, %d per VU",
			currentDoneIters, totalIters, iterations)
		right := []string{progVUs, duration.String(), progIters}
		if spent > duration {
			return 1, right
		}

		spentDuration := pb.GetFixedLengthDuration(spent, duration)
		progDur := fmt.Sprintf("%s/%s", spentDuration, duration)
		right[1] = progDur

		return float64(currentDoneIters) / float64(totalIters), right
	}
	pvi.progress.Modify(pb.WithProgress(progresFn))
	go trackProgress(ctx, maxDurationCtx, regDurationCtx, pvi, progresFn)

	// Actually schedule the VUs and iterations...
	activeVUs := &sync.WaitGroup{}
	defer activeVUs.Wait()

	regDurationDone := regDurationCtx.Done()
	runIteration := getIterationRunner(pvi.executionState, pvi.logger)

	conf := pvi.GetConfig()
	execFn := conf.GetExec().ValueOrZero()
	env := conf.GetEnv()
	tags := conf.GetTags()
	handleVU := func(initVU lib.InitializedVU) {
		ctx, cancel := context.WithCancel(maxDurationCtx)
		defer cancel()

		vu := initVU.Activate(&lib.VUActivationParams{
			RunContext: ctx,
			Exec:       execFn,
			Env:        env,
			Tags:       tags,
			DeactivateCallback: func() {
				pvi.executionState.ReturnVU(initVU, true)
				activeVUs.Done()
			},
		})

		for i := int64(0); i < iterations; i++ {
			select {
			case <-regDurationDone:
				return // don't make more iterations
			default:
				// continue looping
			}
			runIteration(maxDurationCtx, vu)
			atomic.AddUint64(doneIters, 1)
		}
	}

	for i := int64(0); i < numVUs; i++ {
		initializedVU, err := pvi.executionState.GetPlannedVU(pvi.logger, true)
		if err != nil {
			cancel()
			return err
		}
		activeVUs.Add(1)
		go handleVU(initializedVU)
	}

	return nil
}
<commit_msg>Ignore funlen linter for PerVUIterations.Run<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package executor

import (
	"context"
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"github.com/sirupsen/logrus"
	null "gopkg.in/guregu/null.v3"

	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/types"
	"github.com/loadimpact/k6/stats"
	"github.com/loadimpact/k6/ui/pb"
)

const perVUIterationsType = "per-vu-iterations"

func init() {
	lib.RegisterExecutorConfigType(perVUIterationsType, func(name string, rawJSON []byte) (lib.ExecutorConfig, error) {
		config := NewPerVUIterationsConfig(name)
		err := lib.StrictJSONUnmarshal(rawJSON, &config)
		return config, err
	})
}

// PerVUIterationsConfig stores the number of VUs iterations, as well as maxDuration settings
type PerVUIterationsConfig struct {
	BaseConfig
	VUs         null.Int           `json:"vus"`
	Iterations  null.Int           `json:"iterations"`
	MaxDuration types.NullDuration `json:"maxDuration"`
}

// NewPerVUIterationsConfig returns a PerVUIterationsConfig with default values
func NewPerVUIterationsConfig(name string) PerVUIterationsConfig {
	return PerVUIterationsConfig{
		BaseConfig:  NewBaseConfig(name, perVUIterationsType),
		VUs:         null.NewInt(1, false),
		Iterations:  null.NewInt(1, false),
		MaxDuration: types.NewNullDuration(10*time.Minute, false), //TODO: shorten?
	}
}

// Make sure we implement the lib.ExecutorConfig interface
var _ lib.ExecutorConfig = &PerVUIterationsConfig{}

// GetVUs returns the scaled VUs for the executor.
func (pvic PerVUIterationsConfig) GetVUs(et *lib.ExecutionTuple) int64 {
	return et.ES.Scale(pvic.VUs.Int64)
}

// GetIterations returns the UNSCALED iteration count for the executor. It's
// important to note that scaling per-VU iteration executor affects only the
// number of VUs. If we also scaled the iterations, scaling would have quadratic
// effects instead of just linear.
func (pvic PerVUIterationsConfig) GetIterations() int64 {
	return pvic.Iterations.Int64
}

// GetDescription returns a human-readable description of the executor options
func (pvic PerVUIterationsConfig) GetDescription(et *lib.ExecutionTuple) string {
	return fmt.Sprintf("%d iterations for each of %d VUs%s",
		pvic.GetIterations(), pvic.GetVUs(et),
		pvic.getBaseInfo(fmt.Sprintf("maxDuration: %s", pvic.MaxDuration.Duration)))
}

// Validate makes sure all options are configured and valid
func (pvic PerVUIterationsConfig) Validate() []error {
	errors := pvic.BaseConfig.Validate()
	if pvic.VUs.Int64 <= 0 {
		errors = append(errors, fmt.Errorf("the number of VUs should be more than 0"))
	}

	if pvic.Iterations.Int64 <= 0 {
		errors = append(errors, fmt.Errorf("the number of iterations should be more than 0"))
	}

	if time.Duration(pvic.MaxDuration.Duration) < minDuration {
		errors = append(errors, fmt.Errorf(
			"the maxDuration should be at least %s, but is %s", minDuration, pvic.MaxDuration,
		))
	}

	return errors
}

// GetExecutionRequirements returns the number of required VUs to run the
// executor for its whole duration (disregarding any startTime), including the
// maximum waiting time for any iterations to gracefully stop. This is used by
// the execution scheduler in its VU reservation calculations, so it knows how
// many VUs to pre-initialize.
func (pvic PerVUIterationsConfig) GetExecutionRequirements(et *lib.ExecutionTuple) []lib.ExecutionStep {
	return []lib.ExecutionStep{
		{
			TimeOffset: 0,
			PlannedVUs: uint64(pvic.GetVUs(et)),
		},
		{
			TimeOffset: time.Duration(pvic.MaxDuration.Duration + pvic.GracefulStop.Duration),
			PlannedVUs: 0,
		},
	}
}

// NewExecutor creates a new PerVUIterations executor
func (pvic PerVUIterationsConfig) NewExecutor(
	es *lib.ExecutionState, logger *logrus.Entry,
) (lib.Executor, error) {
	return PerVUIterations{
		BaseExecutor: NewBaseExecutor(pvic, es, logger),
		config:       pvic,
	}, nil
}

// HasWork reports whether there is any work to be done for the given execution segment.
func (pvic PerVUIterationsConfig) HasWork(et *lib.ExecutionTuple) bool {
	return pvic.GetVUs(et) > 0 && pvic.GetIterations() > 0
}

// PerVUIterations executes a specific number of iterations with each VU.
type PerVUIterations struct {
	*BaseExecutor
	config PerVUIterationsConfig
}

// Make sure we implement the lib.Executor interface.
var _ lib.Executor = &PerVUIterations{}

// Run executes a specific number of iterations with each configured VU.
// nolint:funlen
func (pvi PerVUIterations) Run(ctx context.Context, out chan<- stats.SampleContainer) (err error) {
	numVUs := pvi.config.GetVUs(pvi.executionState.ExecutionTuple)
	iterations := pvi.config.GetIterations()
	duration := time.Duration(pvi.config.MaxDuration.Duration)
	gracefulStop := pvi.config.GetGracefulStop()

	startTime, maxDurationCtx, regDurationCtx, cancel := getDurationContexts(ctx, duration, gracefulStop)
	defer cancel()

	// Make sure the log and the progress bar have accurate information
	pvi.logger.WithFields(logrus.Fields{
		"vus": numVUs, "iterations": iterations, "maxDuration": duration, "type": pvi.config.GetType(),
	}).Debug("Starting executor run...")

	totalIters := uint64(numVUs * iterations)
	doneIters := new(uint64)

	vusFmt := pb.GetFixedLengthIntFormat(numVUs)
	itersFmt := pb.GetFixedLengthIntFormat(int64(totalIters))
	progresFn := func() (float64, []string) {
		spent := time.Since(startTime)
		progVUs := fmt.Sprintf(vusFmt+" VUs", numVUs)
		currentDoneIters := atomic.LoadUint64(doneIters)
		progIters := fmt.Sprintf(itersFmt+"/"+itersFmt+" iters, %d per VU",
			currentDoneIters, totalIters, iterations)
		right := []string{progVUs, duration.String(), progIters}
		if spent > duration {
			return 1, right
		}

		spentDuration := pb.GetFixedLengthDuration(spent, duration)
		progDur := fmt.Sprintf("%s/%s", spentDuration, duration)
		right[1] = progDur

		return float64(currentDoneIters) / float64(totalIters), right
	}
	pvi.progress.Modify(pb.WithProgress(progresFn))
	go trackProgress(ctx, maxDurationCtx, regDurationCtx, pvi, progresFn)

	// Actually schedule the VUs and iterations...
	activeVUs := &sync.WaitGroup{}
	defer activeVUs.Wait()

	regDurationDone := regDurationCtx.Done()
	runIteration := getIterationRunner(pvi.executionState, pvi.logger)

	conf := pvi.GetConfig()
	execFn := conf.GetExec().ValueOrZero()
	env := conf.GetEnv()
	tags := conf.GetTags()
	handleVU := func(initVU lib.InitializedVU) {
		ctx, cancel := context.WithCancel(maxDurationCtx)
		defer cancel()

		vu := initVU.Activate(&lib.VUActivationParams{
			RunContext: ctx,
			Exec:       execFn,
			Env:        env,
			Tags:       tags,
			DeactivateCallback: func() {
				pvi.executionState.ReturnVU(initVU, true)
				activeVUs.Done()
			},
		})

		for i := int64(0); i < iterations; i++ {
			select {
			case <-regDurationDone:
				return // don't make more iterations
			default:
				// continue looping
			}
			runIteration(maxDurationCtx, vu)
			atomic.AddUint64(doneIters, 1)
		}
	}

	for i := int64(0); i < numVUs; i++ {
		initializedVU, err := pvi.executionState.GetPlannedVU(pvi.logger, true)
		if err != nil {
			cancel()
			return err
		}
		activeVUs.Add(1)
		go handleVU(initializedVU)
	}

	return nil
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package executor

import (
	"context"
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"github.com/sirupsen/logrus"
	null "gopkg.in/guregu/null.v3"

	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/types"
	"github.com/loadimpact/k6/stats"
	"github.com/loadimpact/k6/ui/pb"
)

const sharedIterationsType = "shared-iterations"

func init() {
	lib.RegisterExecutorConfigType(
		sharedIterationsType,
		func(name string, rawJSON []byte) (lib.ExecutorConfig, error) {
			config := NewSharedIterationsConfig(name)
			err := lib.StrictJSONUnmarshal(rawJSON, &config)
			return config, err
		},
	)
}

// SharedIterationsConfig stores the number of VUs iterations, as well as maxDuration settings
type SharedIterationsConfig struct {
	BaseConfig
	VUs         null.Int           `json:"vus"`
	Iterations  null.Int           `json:"iterations"`
	MaxDuration types.NullDuration `json:"maxDuration"`
}

// NewSharedIterationsConfig returns a SharedIterationsConfig with default values
func NewSharedIterationsConfig(name string) SharedIterationsConfig {
	return SharedIterationsConfig{
		BaseConfig:  NewBaseConfig(name, sharedIterationsType),
		VUs:         null.NewInt(1, false),
		Iterations:  null.NewInt(1, false),
		MaxDuration: types.NewNullDuration(10*time.Minute, false), //TODO: shorten?
	}
}

// Make sure we implement the lib.ExecutorConfig interface
var _ lib.ExecutorConfig = &SharedIterationsConfig{}

// GetVUs returns the scaled VUs for the executor.
func (sic SharedIterationsConfig) GetVUs(et *lib.ExecutionTuple) int64 {
	return et.ES.Scale(sic.VUs.Int64)
}

// GetIterations returns the scaled iteration count for the executor.
func (sic SharedIterationsConfig) GetIterations(et *lib.ExecutionTuple) int64 {
	return et.ES.Scale(sic.Iterations.Int64)
}

// GetDescription returns a human-readable description of the executor options
func (sic SharedIterationsConfig) GetDescription(et *lib.ExecutionTuple) string {
	return fmt.Sprintf("%d iterations shared among %d VUs%s",
		sic.GetIterations(et), sic.GetVUs(et),
		sic.getBaseInfo(fmt.Sprintf("maxDuration: %s", sic.MaxDuration.Duration)))
}

// Validate makes sure all options are configured and valid
func (sic SharedIterationsConfig) Validate() []error {
	errors := sic.BaseConfig.Validate()
	if sic.VUs.Int64 <= 0 {
		errors = append(errors, fmt.Errorf("the number of VUs should be more than 0"))
	}

	if sic.Iterations.Int64 < sic.VUs.Int64 {
		errors = append(errors, fmt.Errorf(
			"the number of iterations (%d) shouldn't be less than the number of VUs (%d)",
			sic.Iterations.Int64, sic.VUs.Int64,
		))
	}

	if time.Duration(sic.MaxDuration.Duration) < minDuration {
		errors = append(errors, fmt.Errorf(
			"the maxDuration should be at least %s, but is %s", minDuration, sic.MaxDuration,
		))
	}

	return errors
}

// GetExecutionRequirements returns the number of required VUs to run the
// executor for its whole duration (disregarding any startTime), including the
// maximum waiting time for any iterations to gracefully stop. This is used by
// the execution scheduler in its VU reservation calculations, so it knows how
// many VUs to pre-initialize.
func (sic SharedIterationsConfig) GetExecutionRequirements(et *lib.ExecutionTuple) []lib.ExecutionStep {
	return []lib.ExecutionStep{
		{
			TimeOffset: 0,
			PlannedVUs: uint64(sic.GetVUs(et)),
		},
		{
			TimeOffset: time.Duration(sic.MaxDuration.Duration + sic.GracefulStop.Duration),
			PlannedVUs: 0,
		},
	}
}

// NewExecutor creates a new SharedIterations executor
func (sic SharedIterationsConfig) NewExecutor(
	es *lib.ExecutionState, logger *logrus.Entry,
) (lib.Executor, error) {
	return SharedIterations{
		BaseExecutor: NewBaseExecutor(sic, es, logger),
		config:       sic,
	}, nil
}

// SharedIterations executes a specific total number of iterations, which are
// all shared by the configured VUs.
type SharedIterations struct {
	*BaseExecutor
	config SharedIterationsConfig
}

// Make sure we implement the lib.Executor interface.
var _ lib.Executor = &SharedIterations{}

// HasWork reports whether there is any work to be done for the given execution segment.
func (sic SharedIterationsConfig) HasWork(et *lib.ExecutionTuple) bool {
	return sic.GetVUs(et) > 0 && sic.GetIterations(et) > 0
}

// Run executes a specific total number of iterations, which are all shared by
// the configured VUs.
func (si SharedIterations) Run(ctx context.Context, out chan<- stats.SampleContainer) (err error) {
	numVUs := si.config.GetVUs(si.executionState.ExecutionTuple)
	iterations := si.config.GetIterations(si.executionState.ExecutionTuple)
	duration := time.Duration(si.config.MaxDuration.Duration)
	gracefulStop := si.config.GetGracefulStop()

	startTime, maxDurationCtx, regDurationCtx, cancel := getDurationContexts(ctx, duration, gracefulStop)
	defer cancel()

	// Make sure the log and the progress bar have accurate information
	si.logger.WithFields(logrus.Fields{
		"vus": numVUs, "iterations": iterations, "maxDuration": duration, "type": si.config.GetType(),
	}).Debug("Starting executor run...")

	totalIters := uint64(iterations)
	doneIters := new(uint64)
	vusFmt := pb.GetFixedLengthIntFormat(numVUs)
	itersFmt := pb.GetFixedLengthIntFormat(int64(totalIters))
	progresFn := func() (float64, []string) {
		spent := time.Since(startTime)
		progVUs := fmt.Sprintf(vusFmt+" VUs", numVUs)
		currentDoneIters := atomic.LoadUint64(doneIters)
		progIters := fmt.Sprintf(itersFmt+"/"+itersFmt+" shared iters",
			currentDoneIters, totalIters)
		spentDuration := pb.GetFixedLengthDuration(spent, duration)
		progDur := fmt.Sprintf("%s/%s", spentDuration, duration)
		right := []string{progVUs, progDur, progIters}

		return float64(currentDoneIters) / float64(totalIters), right
	}
	si.progress.Modify(pb.WithProgress(progresFn))
	go trackProgress(ctx, maxDurationCtx, regDurationCtx, si, progresFn)

	// Actually schedule the VUs and iterations...
	activeVUs := &sync.WaitGroup{}
	defer activeVUs.Wait()

	regDurationDone := regDurationCtx.Done()
	runIteration := getIterationRunner(si.executionState, si.logger)

	attemptedIters := new(uint64)
	handleVU := func(initVU lib.InitializedVU) {
		ctx, cancel := context.WithCancel(maxDurationCtx)
		defer cancel()

		vu := initVU.Activate(&lib.VUActivationParams{
			RunContext: ctx,
			DeactivateCallback: func() {
				si.executionState.ReturnVU(initVU, true)
				activeVUs.Done()
			},
		})

		for {
			select {
			case <-regDurationDone:
				return // don't make more iterations
			default:
				// continue looping
			}

			attemptedIterNumber := atomic.AddUint64(attemptedIters, 1)
			if attemptedIterNumber > totalIters {
				return
			}

			runIteration(maxDurationCtx, vu)
			atomic.AddUint64(doneIters, 1)
		}
	}

	for i := int64(0); i < numVUs; i++ {
		initVU, err := si.executionState.GetPlannedVU(si.logger, true)
		if err != nil {
			cancel()
			return err
		}
		activeVUs.Add(1)
		go handleVU(initVU)
	}

	return nil
}
<commit_msg>Ignore funlen linter for SharedIterations.Run<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package executor

import (
	"context"
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"github.com/sirupsen/logrus"
	null "gopkg.in/guregu/null.v3"

	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/types"
	"github.com/loadimpact/k6/stats"
	"github.com/loadimpact/k6/ui/pb"
)

const sharedIterationsType = "shared-iterations"

func init() {
	lib.RegisterExecutorConfigType(
		sharedIterationsType,
		func(name string, rawJSON []byte) (lib.ExecutorConfig, error) {
			config := NewSharedIterationsConfig(name)
			err := lib.StrictJSONUnmarshal(rawJSON, &config)
			return config, err
		},
	)
}

// SharedIterationsConfig stores the number of VUs iterations, as well as maxDuration settings
type SharedIterationsConfig struct {
	BaseConfig
	VUs         null.Int           `json:"vus"`
	Iterations  null.Int           `json:"iterations"`
	MaxDuration types.NullDuration `json:"maxDuration"`
}

// NewSharedIterationsConfig returns a SharedIterationsConfig with default values
func NewSharedIterationsConfig(name string) SharedIterationsConfig {
	return SharedIterationsConfig{
		BaseConfig:  NewBaseConfig(name, sharedIterationsType),
		VUs:         null.NewInt(1, false),
		Iterations:  null.NewInt(1, false),
		MaxDuration: types.NewNullDuration(10*time.Minute, false), //TODO: shorten?
	}
}

// Make sure we implement the lib.ExecutorConfig interface
var _ lib.ExecutorConfig = &SharedIterationsConfig{}

// GetVUs returns the scaled VUs for the executor.
func (sic SharedIterationsConfig) GetVUs(et *lib.ExecutionTuple) int64 {
	return et.ES.Scale(sic.VUs.Int64)
}

// GetIterations returns the scaled iteration count for the executor.
func (sic SharedIterationsConfig) GetIterations(et *lib.ExecutionTuple) int64 {
	return et.ES.Scale(sic.Iterations.Int64)
}

// GetDescription returns a human-readable description of the executor options
func (sic SharedIterationsConfig) GetDescription(et *lib.ExecutionTuple) string {
	return fmt.Sprintf("%d iterations shared among %d VUs%s",
		sic.GetIterations(et), sic.GetVUs(et),
		sic.getBaseInfo(fmt.Sprintf("maxDuration: %s", sic.MaxDuration.Duration)))
}

// Validate makes sure all options are configured and valid
func (sic SharedIterationsConfig) Validate() []error {
	errors := sic.BaseConfig.Validate()
	if sic.VUs.Int64 <= 0 {
		errors = append(errors, fmt.Errorf("the number of VUs should be more than 0"))
	}

	if sic.Iterations.Int64 < sic.VUs.Int64 {
		errors = append(errors, fmt.Errorf(
			"the number of iterations (%d) shouldn't be less than the number of VUs (%d)",
			sic.Iterations.Int64, sic.VUs.Int64,
		))
	}

	if time.Duration(sic.MaxDuration.Duration) < minDuration {
		errors = append(errors, fmt.Errorf(
			"the maxDuration should be at least %s, but is %s", minDuration, sic.MaxDuration,
		))
	}

	return errors
}

// GetExecutionRequirements returns the number of required VUs to run the
// executor for its whole duration (disregarding any startTime), including the
// maximum waiting time for any iterations to gracefully stop. This is used by
// the execution scheduler in its VU reservation calculations, so it knows how
// many VUs to pre-initialize.
func (sic SharedIterationsConfig) GetExecutionRequirements(et *lib.ExecutionTuple) []lib.ExecutionStep {
	return []lib.ExecutionStep{
		{
			TimeOffset: 0,
			PlannedVUs: uint64(sic.GetVUs(et)),
		},
		{
			TimeOffset: time.Duration(sic.MaxDuration.Duration + sic.GracefulStop.Duration),
			PlannedVUs: 0,
		},
	}
}

// NewExecutor creates a new SharedIterations executor
func (sic SharedIterationsConfig) NewExecutor(
	es *lib.ExecutionState, logger *logrus.Entry,
) (lib.Executor, error) {
	return SharedIterations{
		BaseExecutor: NewBaseExecutor(sic, es, logger),
		config:       sic,
	}, nil
}

// SharedIterations executes a specific total number of iterations, which are
// all shared by the configured VUs.
type SharedIterations struct {
	*BaseExecutor
	config SharedIterationsConfig
}

// Make sure we implement the lib.Executor interface.
var _ lib.Executor = &SharedIterations{}

// HasWork reports whether there is any work to be done for the given execution segment.
func (sic SharedIterationsConfig) HasWork(et *lib.ExecutionTuple) bool {
	return sic.GetVUs(et) > 0 && sic.GetIterations(et) > 0
}

// Run executes a specific total number of iterations, which are all shared by
// the configured VUs.
// nolint:funlen
func (si SharedIterations) Run(ctx context.Context, out chan<- stats.SampleContainer) (err error) {
	numVUs := si.config.GetVUs(si.executionState.ExecutionTuple)
	iterations := si.config.GetIterations(si.executionState.ExecutionTuple)
	duration := time.Duration(si.config.MaxDuration.Duration)
	gracefulStop := si.config.GetGracefulStop()

	startTime, maxDurationCtx, regDurationCtx, cancel := getDurationContexts(ctx, duration, gracefulStop)
	defer cancel()

	// Make sure the log and the progress bar have accurate information
	si.logger.WithFields(logrus.Fields{
		"vus": numVUs, "iterations": iterations, "maxDuration": duration, "type": si.config.GetType(),
	}).Debug("Starting executor run...")

	totalIters := uint64(iterations)
	doneIters := new(uint64)
	vusFmt := pb.GetFixedLengthIntFormat(numVUs)
	itersFmt := pb.GetFixedLengthIntFormat(int64(totalIters))
	progresFn := func() (float64, []string) {
		spent := time.Since(startTime)
		progVUs := fmt.Sprintf(vusFmt+" VUs", numVUs)
		currentDoneIters := atomic.LoadUint64(doneIters)
		progIters := fmt.Sprintf(itersFmt+"/"+itersFmt+" shared iters",
			currentDoneIters, totalIters)
		spentDuration := pb.GetFixedLengthDuration(spent, duration)
		progDur := fmt.Sprintf("%s/%s", spentDuration, duration)
		right := []string{progVUs, progDur, progIters}

		return float64(currentDoneIters) / float64(totalIters), right
	}
	si.progress.Modify(pb.WithProgress(progresFn))
	go trackProgress(ctx, maxDurationCtx, regDurationCtx, si, progresFn)

	// Actually schedule the VUs and iterations...
	activeVUs := &sync.WaitGroup{}
	defer activeVUs.Wait()

	regDurationDone := regDurationCtx.Done()
	runIteration := getIterationRunner(si.executionState, si.logger)

	attemptedIters := new(uint64)
	handleVU := func(initVU lib.InitializedVU) {
		ctx, cancel := context.WithCancel(maxDurationCtx)
		defer cancel()

		vu := initVU.Activate(&lib.VUActivationParams{
			RunContext: ctx,
			DeactivateCallback: func() {
				si.executionState.ReturnVU(initVU, true)
				activeVUs.Done()
			},
		})

		for {
			select {
			case <-regDurationDone:
				return // don't make more iterations
			default:
				// continue looping
			}

			attemptedIterNumber := atomic.AddUint64(attemptedIters, 1)
			if attemptedIterNumber > totalIters {
				return
			}

			runIteration(maxDurationCtx, vu)
			atomic.AddUint64(doneIters, 1)
		}
	}

	for i := int64(0); i < numVUs; i++ {
		initVU, err := si.executionState.GetPlannedVU(si.logger, true)
		if err != nil {
			cancel()
			return err
		}
		activeVUs.Add(1)
		go handleVU(initVU)
	}

	return nil
}
<|endoftext|>


<commit_before>package service

import (
	"errors"
	"github.com/timeredbull/tsuru/api/auth"
	"github.com/timeredbull/tsuru/db"
	"github.com/timeredbull/tsuru/log"
	"labix.org/v2/mgo/bson"
	"strings"
)

const OnNewInstance = "on-new-instance"

type Service struct {
	Name         string `bson:"_id"`
	Endpoint     map[string]string
	Bootstrap    map[string]string
	OwnerTeams   []string `bson:"owner_teams"`
	Teams        []string
	Status       string
	Doc          string
	IsRestricted bool `bson:"is_restricted"`
}

func (s *Service) Log(out []byte) {
	log.Printf(string(out))
}

func (s *Service) Get() error {
	query := bson.M{"_id": s.Name, "status": bson.M{"$ne": "deleted"}}
	return db.Session.Services().Find(query).One(&s)
}

func (s *Service) Create() error {
	s.Status = "created"
	s.IsRestricted = false
	err := db.Session.Services().Insert(s)
	return err
}

func (s *Service) Update() error {
	return db.Session.Services().Update(bson.M{"_id": s.Name}, s)
}

func (s *Service) Delete() error {
	s.Status = "deleted"
	return db.Session.Services().Update(bson.M{"_id": s.Name}, s)
}

func (s *Service) GetClient(endpoint string) (cli *Client, err error) {
	if e, ok := s.Endpoint[endpoint]; ok {
		if !strings.HasPrefix(e, "http://") {
			e = "http://" + e
		}
		cli = &Client{endpoint: e}
	} else {
		err = errors.New("Unknown endpoint: " + endpoint)
	}
	return
}

func (s *Service) findTeam(team *auth.Team) int {
	for i, t := range s.Teams {
		if team.Name == t {
			return i
		}
	}
	return -1
}

func (s *Service) HasTeam(team *auth.Team) bool {
	return s.findTeam(team) > -1
}

func (s *Service) GrantAccess(team *auth.Team) error {
	if s.HasTeam(team) {
		return errors.New("This team already has access to this service")
	}
	s.Teams = append(s.Teams, team.Name)
	return nil
}

func (s *Service) RevokeAccess(team *auth.Team) error {
	index := s.findTeam(team)
	if index < 0 {
		return errors.New("This team does not have access to this service")
	}
	last := len(s.Teams) - 1
	s.Teams[index] = s.Teams[last]
	s.Teams = s.Teams[:last]
	return nil
}

func GetServicesNames(services []Service) []string {
	sNames := make([]string, len(services))
	for i, s := range services {
		sNames[i] = s.Name
	}
	return sNames
}
<commit_msg>api.service: not setting IsRestricted to false, since it's already false by default<commit_after>package service

import (
	"errors"
	"github.com/timeredbull/tsuru/api/auth"
	"github.com/timeredbull/tsuru/db"
	"github.com/timeredbull/tsuru/log"
	"labix.org/v2/mgo/bson"
	"strings"
)

const OnNewInstance = "on-new-instance"

type Service struct {
	Name         string `bson:"_id"`
	Endpoint     map[string]string
	Bootstrap    map[string]string
	OwnerTeams   []string `bson:"owner_teams"`
	Teams        []string
	Status       string
	Doc          string
	IsRestricted bool `bson:"is_restricted"`
}

func (s *Service) Log(out []byte) {
	log.Printf(string(out))
}

func (s *Service) Get() error {
	query := bson.M{"_id": s.Name, "status": bson.M{"$ne": "deleted"}}
	return db.Session.Services().Find(query).One(&s)
}

func (s *Service) Create() error {
	s.Status = "created"
	err := db.Session.Services().Insert(s)
	return err
}

func (s *Service) Update() error {
	return db.Session.Services().Update(bson.M{"_id": s.Name}, s)
}

func (s *Service) Delete() error {
	s.Status = "deleted"
	return db.Session.Services().Update(bson.M{"_id": s.Name}, s)
}

func (s *Service) GetClient(endpoint string) (cli *Client, err error) {
	if e, ok := s.Endpoint[endpoint]; ok {
		if !strings.HasPrefix(e, "http://") {
			e = "http://" + e
		}
		cli = &Client{endpoint: e}
	} else {
		err = errors.New("Unknown endpoint: " + endpoint)
	}
	return
}

func (s *Service) findTeam(team *auth.Team) int {
	for i, t := range s.Teams {
		if team.Name == t {
			return i
		}
	}
	return -1
}

func (s *Service) HasTeam(team *auth.Team) bool {
	return s.findTeam(team) > -1
}

func (s *Service) GrantAccess(team *auth.Team) error {
	if s.HasTeam(team) {
		return errors.New("This team already has access to this service")
	}
	s.Teams = append(s.Teams, team.Name)
	return nil
}

func (s *Service) RevokeAccess(team *auth.Team) error {
	index := s.findTeam(team)
	if index < 0 {
		return errors.New("This team does not have access to this service")
	}
	last := len(s.Teams) - 1
	s.Teams[index] = s.Teams[last]
	s.Teams = s.Teams[:last]
	return nil
}

func GetServicesNames(services []Service) []string {
	sNames := make([]string, len(services))
	for i, s := range services {
		sNames[i] = s.Name
	}
	return sNames
}
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.47"
<commit_msg>functions: 0.3.48 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.48"
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.415"
<commit_msg>fnserver: 0.3.416 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.416"
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.162"
<commit_msg>functions: 0.3.163 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.163"
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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 apiserver

import (
	"fmt"
	"net"

	"k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup.k8s.io/v1"
	testgroupetcd "k8s.io/kubernetes/examples/apiserver/rest"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/rest"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/apimachinery/registered"
	"k8s.io/kubernetes/pkg/genericapiserver"
	genericoptions "k8s.io/kubernetes/pkg/genericapiserver/options"
	genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
	"k8s.io/kubernetes/pkg/storage/storagebackend"

	// Install the testgroup API
	_ "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup.k8s.io/install"
)

const (
	// Ports on which to run the server.
	// Explicitly setting these to a different value than the default values, to prevent this from clashing with a local cluster.
	InsecurePort = 8081
)

func newStorageFactory() genericapiserver.StorageFactory {
	config := storagebackend.Config{
		Prefix:     genericoptions.DefaultEtcdPathPrefix,
		ServerList: []string{"http://127.0.0.1:2379"},
	}
	storageFactory := genericapiserver.NewDefaultStorageFactory(config, "application/json", api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), genericapiserver.NewResourceConfig())

	return storageFactory
}

func NewServerRunOptions() *genericoptions.ServerRunOptions {
	serverOptions := genericoptions.NewServerRunOptions().WithEtcdOptions()
	serverOptions.InsecurePort = InsecurePort
	return serverOptions
}

func Run(serverOptions *genericoptions.ServerRunOptions) error {
	// Set ServiceClusterIPRange
	_, serviceClusterIPRange, _ := net.ParseCIDR("10.0.0.0/24")
	serverOptions.ServiceClusterIPRange = *serviceClusterIPRange
	serverOptions.StorageConfig.ServerList = []string{"http://127.0.0.1:2379"}
	genericvalidation.ValidateRunOptions(serverOptions)
	genericvalidation.VerifyEtcdServersList(serverOptions)
	config := genericapiserver.NewConfig(serverOptions)
	config.Serializer = api.Codecs
	s, err := genericapiserver.New(config)
	if err != nil {
		return fmt.Errorf("Error in bringing up the server: %v", err)
	}

	groupVersion := v1.SchemeGroupVersion
	groupName := groupVersion.Group
	groupMeta, err := registered.Group(groupName)
	if err != nil {
		return fmt.Errorf("%v", err)
	}
	storageFactory := newStorageFactory()
	storageConfig, err := storageFactory.NewConfig(unversioned.GroupResource{Group: groupName, Resource: "testtype"})
	if err != nil {
		return fmt.Errorf("Unable to get storage config: %v", err)
	}

	restStorageMap := map[string]rest.Storage{
		"testtypes": testgroupetcd.NewREST(storageConfig, s.StorageDecorator()),
	}
	apiGroupInfo := genericapiserver.APIGroupInfo{
		GroupMeta: *groupMeta,
		VersionedResourcesStorageMap: map[string]map[string]rest.Storage{
			groupVersion.Version: restStorageMap,
		},
		Scheme:               api.Scheme,
		NegotiatedSerializer: api.Codecs,
	}
	if err := s.InstallAPIGroups([]genericapiserver.APIGroupInfo{apiGroupInfo}); err != nil {
		return fmt.Errorf("Error in installing API: %v", err)
	}
	s.Run(serverOptions)
	return nil
}
<commit_msg>refactor genericapiserver new to combine initialization<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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 apiserver

import (
	"fmt"
	"net"

	"k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup.k8s.io/v1"
	testgroupetcd "k8s.io/kubernetes/examples/apiserver/rest"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/rest"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/apimachinery/registered"
	"k8s.io/kubernetes/pkg/genericapiserver"
	genericoptions "k8s.io/kubernetes/pkg/genericapiserver/options"
	genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
	"k8s.io/kubernetes/pkg/storage/storagebackend"

	// Install the testgroup API
	_ "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup.k8s.io/install"
)

const (
	// Ports on which to run the server.
	// Explicitly setting these to a different value than the default values, to prevent this from clashing with a local cluster.
	InsecurePort = 8081
)

func newStorageFactory() genericapiserver.StorageFactory {
	config := storagebackend.Config{
		Prefix:     genericoptions.DefaultEtcdPathPrefix,
		ServerList: []string{"http://127.0.0.1:2379"},
	}
	storageFactory := genericapiserver.NewDefaultStorageFactory(config, "application/json", api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), genericapiserver.NewResourceConfig())

	return storageFactory
}

func NewServerRunOptions() *genericoptions.ServerRunOptions {
	serverOptions := genericoptions.NewServerRunOptions().WithEtcdOptions()
	serverOptions.InsecurePort = InsecurePort
	return serverOptions
}

func Run(serverOptions *genericoptions.ServerRunOptions) error {
	// Set ServiceClusterIPRange
	_, serviceClusterIPRange, _ := net.ParseCIDR("10.0.0.0/24")
	serverOptions.ServiceClusterIPRange = *serviceClusterIPRange
	serverOptions.StorageConfig.ServerList = []string{"http://127.0.0.1:2379"}
	genericvalidation.ValidateRunOptions(serverOptions)
	genericvalidation.VerifyEtcdServersList(serverOptions)
	config := genericapiserver.NewConfig(serverOptions)
	config.Serializer = api.Codecs
	s, err := config.New()
	if err != nil {
		return fmt.Errorf("Error in bringing up the server: %v", err)
	}

	groupVersion := v1.SchemeGroupVersion
	groupName := groupVersion.Group
	groupMeta, err := registered.Group(groupName)
	if err != nil {
		return fmt.Errorf("%v", err)
	}
	storageFactory := newStorageFactory()
	storageConfig, err := storageFactory.NewConfig(unversioned.GroupResource{Group: groupName, Resource: "testtype"})
	if err != nil {
		return fmt.Errorf("Unable to get storage config: %v", err)
	}

	restStorageMap := map[string]rest.Storage{
		"testtypes": testgroupetcd.NewREST(storageConfig, s.StorageDecorator()),
	}
	apiGroupInfo := genericapiserver.APIGroupInfo{
		GroupMeta: *groupMeta,
		VersionedResourcesStorageMap: map[string]map[string]rest.Storage{
			groupVersion.Version: restStorageMap,
		},
		Scheme:               api.Scheme,
		NegotiatedSerializer: api.Codecs,
	}
	if err := s.InstallAPIGroups([]genericapiserver.APIGroupInfo{apiGroupInfo}); err != nil {
		return fmt.Errorf("Error in installing API: %v", err)
	}
	s.Run(serverOptions)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"code.google.com/p/log4go"
	"fmt"
	. "github.com/limetext/lime/backend/util"
	"reflect"
	"regexp"
	"strings"
	"time"
)

type (
	CommandHandler interface {
		Unregister(string) error
		RegisterWithDefault(cmd interface{}) error
		Register(name string, cmd interface{}) error
		// TODO(q): Do the commands need to be split in separate lists?
		RunWindowCommand(*Window, string, Args) error
		RunTextCommand(*View, string, Args) error
		RunApplicationCommand(string, Args) error
	}

	appcmd         map[string]Command
	textcmd        map[string]Command
	wndcmd         map[string]Command
	commandHandler struct {
		ApplicationCommands appcmd
		TextCommands        textcmd
		WindowCommands      wndcmd
		log                 bool
		verbose             bool
	}
)

var casere = regexp.MustCompile(`([A-Z])`)

func PascalCaseToSnakeCase(in string) string {
	first := true
	return casere.ReplaceAllStringFunc(in, func(in string) string {
		if first {
			first = false
			return strings.ToLower(in)
		}
		return "_" + strings.ToLower(in)
	})

}

func DefaultName(cmd interface{}) string {
	name := reflect.TypeOf(cmd).Elem().Name()
	return PascalCaseToSnakeCase(strings.TrimSuffix(name, "Command"))
}

// If the cmd implements the CustomInit interface, its Init function
// is called, otherwise the fields of th cmd's underlying struct type
// will be enumerated and match against the dictionary keys in args,
// or if the key isn't provided in args, the Zero value will be used.
func (ch *commandHandler) init(cmd interface{}, args Args) error {
	if in, ok := cmd.(CustomInit); ok {
		return in.Init(args)
	}
	v := reflect.ValueOf(cmd).Elem()
	t := v.Type()
	for i := 0; i < v.NumField(); i++ {
		ft := t.Field(i)
		f := v.Field(i)
		if ft.Anonymous || !f.CanSet() {
			continue
		}
		key := PascalCaseToSnakeCase(ft.Name)
		fv, ok := args[key]
		if !ok {
			fv = reflect.Zero(ft.Type).Interface()
		}
		if f.CanAddr() {
			if f2, ok := f.Addr().Interface().(CustomSet); ok {
				if err := f2.Set(fv); err != nil {
					return err
				}
				continue
			}
		}
		f.Set(reflect.ValueOf(fv))
	}
	return nil
}

func (ch *commandHandler) RunWindowCommand(wnd *Window, name string, args Args) error {
	lvl := log4go.FINE
	p := Prof.Enter("wc")
	defer p.Exit()
	if ch.log {
		lvl = log4go.DEBUG
	}
	log4go.Logf(lvl, "Running window command: %s %v", name, args)
	t := time.Now()
	if c, ok := ch.WindowCommands[name].(WindowCommand); c != nil && ok {
		if err := ch.init(c, args); err != nil && ch.verbose {
			log4go.Debug("Command initialization failed: %s", err)
			return err
		} else if err := wnd.runCommand(c, name); err != nil {
			log4go.Logf(lvl+1, "Command execution failed: %s", err)
			return err
		} else {
			log4go.Logf(lvl, "Ran Window command: %s %s", name, time.Since(t))
		}
	} else {
		log4go.Logf(lvl, "No such window command: %s", name)
	}
	return nil
}

func (ch *commandHandler) RunTextCommand(view *View, name string, args Args) error {
	lvl := log4go.FINE
	p := Prof.Enter("tc")
	defer p.Exit()
	t := time.Now()
	if ch.log {
		lvl = log4go.DEBUG
	}
	log4go.Logf(lvl, "Running text command: %s %v", name, args)
	if c, ok := ch.TextCommands[name].(TextCommand); c != nil && ok {
		if err := ch.init(c, args); err != nil && ch.verbose {
			log4go.Debug("Command initialization failed: %s", err)
			return err
		} else if err := view.runCommand(c, name); err != nil {
			log4go.Logf(lvl, "Command execution failed: %s", err)
			return err
		}
	} else if w := view.Window(); w != nil {
		if c, ok := ch.WindowCommands[name].(WindowCommand); c != nil && ok {
			if err := w.runCommand(c, name); err != nil {
				log4go.Logf(lvl, "Command execution failed: %s", err)
				return err
			}
		}
	}
	log4go.Logf(lvl, "Ran text command: %s %s", name, time.Since(t))
	return nil
}

func (ch *commandHandler) RunApplicationCommand(name string, args Args) error {
	p := Prof.Enter("ac")
	defer p.Exit()
	if ch.log {
		log4go.Info("Running application command: %s %v", name, args)
	} else {
		log4go.Fine("Running application command: %s %v", name, args)
	}
	if c, ok := ch.ApplicationCommands[name].(ApplicationCommand); c != nil && ok {
		if err := ch.init(c, args); err != nil && ch.verbose {
			log4go.Debug("Command initialization failed: %s", err)
			return err
		} else if err := c.Run(); err != nil && ch.verbose {
			log4go.Debug("Command execution failed: %s", err)
			return err
		}
	}
	return nil
}

func (ch *commandHandler) Unregister(name string) error {
	if _, ok := ch.ApplicationCommands[name]; ok {
		ch.ApplicationCommands[name] = nil
	} else if _, ok := ch.WindowCommands[name]; ok {
		ch.WindowCommands[name] = nil
	} else if _, ok := ch.TextCommands[name]; ok {
		ch.TextCommands[name] = nil
	} else {
		return fmt.Errorf("%s wasn't a registered command", name)
	}
	return nil
}

func (ch *commandHandler) RegisterWithDefault(cmd interface{}) error {
	return ch.Register(DefaultName(cmd), cmd)
}

func (ch *commandHandler) Register(name string, cmd interface{}) error {
	var r = false
	log4go.Finest("Want to register %s", name)
	if ac, ok := cmd.(ApplicationCommand); ok {
		if _, ok := ch.ApplicationCommands[name]; ok {
			return fmt.Errorf("%s is already a registered command", name)
		}
		r = true
		ch.ApplicationCommands[name] = ac
	}
	if wc, ok := cmd.(WindowCommand); ok {
		if _, ok := ch.WindowCommands[name]; ok {
			return fmt.Errorf("%s is already a registered command", name)
		}
		r = true
		ch.WindowCommands[name] = wc
	}
	if tc, ok := cmd.(TextCommand); ok {
		if _, ok := ch.TextCommands[name]; ok {
			return fmt.Errorf("%s is already a registered command", name)
		}
		r = true
		ch.TextCommands[name] = tc
	}
	if !r {
		return fmt.Errorf("Command wasn't registered in any list: %s", name)
	} else if ch.verbose {
		log4go.Finest("Successfully registered command %s", name)
	}
	return nil
}
<commit_msg>found a typo in a comment<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"code.google.com/p/log4go"
	"fmt"
	. "github.com/limetext/lime/backend/util"
	"reflect"
	"regexp"
	"strings"
	"time"
)

type (
	CommandHandler interface {
		Unregister(string) error
		RegisterWithDefault(cmd interface{}) error
		Register(name string, cmd interface{}) error
		// TODO(q): Do the commands need to be split in separate lists?
		RunWindowCommand(*Window, string, Args) error
		RunTextCommand(*View, string, Args) error
		RunApplicationCommand(string, Args) error
	}

	appcmd         map[string]Command
	textcmd        map[string]Command
	wndcmd         map[string]Command
	commandHandler struct {
		ApplicationCommands appcmd
		TextCommands        textcmd
		WindowCommands      wndcmd
		log                 bool
		verbose             bool
	}
)

var casere = regexp.MustCompile(`([A-Z])`)

func PascalCaseToSnakeCase(in string) string {
	first := true
	return casere.ReplaceAllStringFunc(in, func(in string) string {
		if first {
			first = false
			return strings.ToLower(in)
		}
		return "_" + strings.ToLower(in)
	})

}

func DefaultName(cmd interface{}) string {
	name := reflect.TypeOf(cmd).Elem().Name()
	return PascalCaseToSnakeCase(strings.TrimSuffix(name, "Command"))
}

// If the cmd implements the CustomInit interface, its Init function
// is called, otherwise the fields of the cmd's underlying struct type
// will be enumerated and match against the dictionary keys in args,
// or if the key isn't provided in args, the Zero value will be used.
func (ch *commandHandler) init(cmd interface{}, args Args) error {
	if in, ok := cmd.(CustomInit); ok {
		return in.Init(args)
	}
	v := reflect.ValueOf(cmd).Elem()
	t := v.Type()
	for i := 0; i < v.NumField(); i++ {
		ft := t.Field(i)
		f := v.Field(i)
		if ft.Anonymous || !f.CanSet() {
			continue
		}
		key := PascalCaseToSnakeCase(ft.Name)
		fv, ok := args[key]
		if !ok {
			fv = reflect.Zero(ft.Type).Interface()
		}
		if f.CanAddr() {
			if f2, ok := f.Addr().Interface().(CustomSet); ok {
				if err := f2.Set(fv); err != nil {
					return err
				}
				continue
			}
		}
		f.Set(reflect.ValueOf(fv))
	}
	return nil
}

func (ch *commandHandler) RunWindowCommand(wnd *Window, name string, args Args) error {
	lvl := log4go.FINE
	p := Prof.Enter("wc")
	defer p.Exit()
	if ch.log {
		lvl = log4go.DEBUG
	}
	log4go.Logf(lvl, "Running window command: %s %v", name, args)
	t := time.Now()
	if c, ok := ch.WindowCommands[name].(WindowCommand); c != nil && ok {
		if err := ch.init(c, args); err != nil && ch.verbose {
			log4go.Debug("Command initialization failed: %s", err)
			return err
		} else if err := wnd.runCommand(c, name); err != nil {
			log4go.Logf(lvl+1, "Command execution failed: %s", err)
			return err
		} else {
			log4go.Logf(lvl, "Ran Window command: %s %s", name, time.Since(t))
		}
	} else {
		log4go.Logf(lvl, "No such window command: %s", name)
	}
	return nil
}

func (ch *commandHandler) RunTextCommand(view *View, name string, args Args) error {
	lvl := log4go.FINE
	p := Prof.Enter("tc")
	defer p.Exit()
	t := time.Now()
	if ch.log {
		lvl = log4go.DEBUG
	}
	log4go.Logf(lvl, "Running text command: %s %v", name, args)
	if c, ok := ch.TextCommands[name].(TextCommand); c != nil && ok {
		if err := ch.init(c, args); err != nil && ch.verbose {
			log4go.Debug("Command initialization failed: %s", err)
			return err
		} else if err := view.runCommand(c, name); err != nil {
			log4go.Logf(lvl, "Command execution failed: %s", err)
			return err
		}
	} else if w := view.Window(); w != nil {
		if c, ok := ch.WindowCommands[name].(WindowCommand); c != nil && ok {
			if err := w.runCommand(c, name); err != nil {
				log4go.Logf(lvl, "Command execution failed: %s", err)
				return err
			}
		}
	}
	log4go.Logf(lvl, "Ran text command: %s %s", name, time.Since(t))
	return nil
}

func (ch *commandHandler) RunApplicationCommand(name string, args Args) error {
	p := Prof.Enter("ac")
	defer p.Exit()
	if ch.log {
		log4go.Info("Running application command: %s %v", name, args)
	} else {
		log4go.Fine("Running application command: %s %v", name, args)
	}
	if c, ok := ch.ApplicationCommands[name].(ApplicationCommand); c != nil && ok {
		if err := ch.init(c, args); err != nil && ch.verbose {
			log4go.Debug("Command initialization failed: %s", err)
			return err
		} else if err := c.Run(); err != nil && ch.verbose {
			log4go.Debug("Command execution failed: %s", err)
			return err
		}
	}
	return nil
}

func (ch *commandHandler) Unregister(name string) error {
	if _, ok := ch.ApplicationCommands[name]; ok {
		ch.ApplicationCommands[name] = nil
	} else if _, ok := ch.WindowCommands[name]; ok {
		ch.WindowCommands[name] = nil
	} else if _, ok := ch.TextCommands[name]; ok {
		ch.TextCommands[name] = nil
	} else {
		return fmt.Errorf("%s wasn't a registered command", name)
	}
	return nil
}

func (ch *commandHandler) RegisterWithDefault(cmd interface{}) error {
	return ch.Register(DefaultName(cmd), cmd)
}

func (ch *commandHandler) Register(name string, cmd interface{}) error {
	var r = false
	log4go.Finest("Want to register %s", name)
	if ac, ok := cmd.(ApplicationCommand); ok {
		if _, ok := ch.ApplicationCommands[name]; ok {
			return fmt.Errorf("%s is already a registered command", name)
		}
		r = true
		ch.ApplicationCommands[name] = ac
	}
	if wc, ok := cmd.(WindowCommand); ok {
		if _, ok := ch.WindowCommands[name]; ok {
			return fmt.Errorf("%s is already a registered command", name)
		}
		r = true
		ch.WindowCommands[name] = wc
	}
	if tc, ok := cmd.(TextCommand); ok {
		if _, ok := ch.TextCommands[name]; ok {
			return fmt.Errorf("%s is already a registered command", name)
		}
		r = true
		ch.TextCommands[name] = tc
	}
	if !r {
		return fmt.Errorf("Command wasn't registered in any list: %s", name)
	} else if ch.verbose {
		log4go.Finest("Successfully registered command %s", name)
	}
	return nil
}
<|endoftext|>


<commit_before>// returns data points from Win32_Service
// https://msdn.microsoft.com/en-us/library/aa394418(v=vs.85).aspx - Win32_Service class
package collector

import (
	"bytes"
	"strings"

	"github.com/StackExchange/wmi"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/log"
	"gopkg.in/alecthomas/kingpin.v2"
)

func init() {
	Factories["service"] = NewserviceCollector
}

var (
	serviceWhereClause = kingpin.Flag(
		"collector.service.services-where",
		"WQL 'where' clause to use in WMI metrics query. Limits the response to the services you specify and reduces the size of the response.",
	).Default("").String()
)

// A serviceCollector is a Prometheus collector for WMI Win32_Service metrics
type serviceCollector struct {
	State     *prometheus.Desc
	StartMode *prometheus.Desc

	queryWhereClause string
}

// NewserviceCollector ...
func NewserviceCollector() (Collector, error) {
	const subsystem = "service"

	var wc bytes.Buffer
	if *serviceWhereClause != "" {
		wc.WriteString("WHERE ")
		wc.WriteString(*serviceWhereClause)
	} else {
		log.Warn("No where-clause specified for service collector. This will generate a very large number of metrics!")
	}

	return &serviceCollector{
		State: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "state"),
			"The state of the service (State)",
			[]string{"name", "state"},
			nil,
		),
		StartMode: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "start_mode"),
			"The start mode of the service (StartMode)",
			[]string{"name", "start_mode"},
			nil,
		),
		queryWhereClause: wc.String(),
	}, nil
}

// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *serviceCollector) Collect(ch chan<- prometheus.Metric) error {
	if desc, err := c.collect(ch); err != nil {
		log.Error("failed collecting service metrics:", desc, err)
		return err
	}
	return nil
}

type Win32_Service struct {
	Name      string
	State     string
	StartMode string
}

var (
	allStates = []string{
		"stopped",
		"start pending",
		"stop pending",
		"running",
		"continue pending",
		"pause pending",
		"paused",
		"unknown",
	}
	allStartModes = []string{
		"boot",
		"system",
		"auto",
		"manual",
		"disabled",
	}
)

func (c *serviceCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
	var dst []Win32_Service
	q := wmi.CreateQuery(&dst, c.queryWhereClause)
	if err := wmi.Query(q, &dst); err != nil {
		return nil, err
	}

	for _, service := range dst {
		for _, state := range allStates {
			isCurrentState := 0.0
			if state == strings.ToLower(service.State) {
				isCurrentState = 1.0
			}
			ch <- prometheus.MustNewConstMetric(
				c.State,
				prometheus.GaugeValue,
				isCurrentState,
				strings.ToLower(service.Name),
				state,
			)
		}

		for _, startMode := range allStartModes {
			isCurrentStartMode := 0.0
			if startMode == strings.ToLower(service.StartMode) {
				isCurrentStartMode = 1.0
			}
			ch <- prometheus.MustNewConstMetric(
				c.StartMode,
				prometheus.GaugeValue,
				isCurrentStartMode,
				strings.ToLower(service.Name),
				startMode,
			)
		}
	}
	return nil, nil
}
<commit_msg>Add status metric for service-collector<commit_after>// returns data points from Win32_Service
// https://msdn.microsoft.com/en-us/library/aa394418(v=vs.85).aspx - Win32_Service class
package collector

import (
	"bytes"
	"strings"

	"github.com/StackExchange/wmi"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/log"
	"gopkg.in/alecthomas/kingpin.v2"
)

func init() {
	Factories["service"] = NewserviceCollector
}

var (
	serviceWhereClause = kingpin.Flag(
		"collector.service.services-where",
		"WQL 'where' clause to use in WMI metrics query. Limits the response to the services you specify and reduces the size of the response.",
	).Default("").String()
)

// A serviceCollector is a Prometheus collector for WMI Win32_Service metrics
type serviceCollector struct {
	State     *prometheus.Desc
	StartMode *prometheus.Desc
	Status    *prometheus.Desc

	queryWhereClause string
}

// NewserviceCollector ...
func NewserviceCollector() (Collector, error) {
	const subsystem = "service"

	var wc bytes.Buffer
	if *serviceWhereClause != "" {
		wc.WriteString("WHERE ")
		wc.WriteString(*serviceWhereClause)
	} else {
		log.Warn("No where-clause specified for service collector. This will generate a very large number of metrics!")
	}

	return &serviceCollector{
		State: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "state"),
			"The state of the service (State)",
			[]string{"name", "state"},
			nil,
		),
		StartMode: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "start_mode"),
			"The start mode of the service (StartMode)",
			[]string{"name", "start_mode"},
			nil,
		),
		Status: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, subsystem, "status"),
			"The status of the service (Status)",
			[]string{"name", "status"},
			nil,
		),
		queryWhereClause: wc.String(),
	}, nil
}

// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *serviceCollector) Collect(ch chan<- prometheus.Metric) error {
	if desc, err := c.collect(ch); err != nil {
		log.Error("failed collecting service metrics:", desc, err)
		return err
	}
	return nil
}

type Win32_Service struct {
	Name      string
	State     string
	Status    string
	StartMode string
}

var (
	allStates = []string{
		"stopped",
		"start pending",
		"stop pending",
		"running",
		"continue pending",
		"pause pending",
		"paused",
		"unknown",
	}
	allStartModes = []string{
		"boot",
		"system",
		"auto",
		"manual",
		"disabled",
	}
	allStatuses = []string{
		"ok",
		"error",
		"degraded",
		"unknown",
		"pred fail",
		"starting",
		"stopping",
		"service",
		"stressed",
		"nonrecover",
		"no contact",
		"lost comm",
	}
)

func (c *serviceCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
	var dst []Win32_Service
	q := wmi.CreateQuery(&dst, c.queryWhereClause)
	if err := wmi.Query(q, &dst); err != nil {
		return nil, err
	}

	for _, service := range dst {
		for _, state := range allStates {
			isCurrentState := 0.0
			if state == strings.ToLower(service.State) {
				isCurrentState = 1.0
			}
			ch <- prometheus.MustNewConstMetric(
				c.State,
				prometheus.GaugeValue,
				isCurrentState,
				strings.ToLower(service.Name),
				state,
			)
		}

		for _, startMode := range allStartModes {
			isCurrentStartMode := 0.0
			if startMode == strings.ToLower(service.StartMode) {
				isCurrentStartMode = 1.0
			}
			ch <- prometheus.MustNewConstMetric(
				c.StartMode,
				prometheus.GaugeValue,
				isCurrentStartMode,
				strings.ToLower(service.Name),
				startMode,
			)
		}

		for _, status := range allStatuses {
			isCurrentStatus := 0.0
			if status == strings.ToLower(service.Status) {
				isCurrentStatus = 1.0
			}
			ch <- prometheus.MustNewConstMetric(
				c.Status,
				prometheus.GaugeValue,
				isCurrentStatus,
				strings.ToLower(service.Name),
				status,
			)
		}
	}
	return nil, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/base64"
	"log"
	"strconv"
	"strings"
	"sync"
)

var imageFilenames map[string]string

type Image struct {
	updateIdx int
	userid    string
	mimetype  string
	data      []byte
}

type ImageCache interface {
	Update(userId string, image string) string

	Get(imageId string) *Image

	DeleteUserImage(userId string)
}

type imageCache struct {
	images     map[string]*Image
	userImages map[string]string
	mutex      sync.RWMutex
}

func NewImageCache() ImageCache {
	result := &imageCache{}
	result.images = make(map[string]*Image)
	result.userImages = make(map[string]string)
	if imageFilenames == nil {
		imageFilenames = map[string]string{
			"image/png":  "picture.png",
			"image/jpeg": "picture.jpg",
			"image/gif":  "picture.gif",
		}
	}
	return result
}

func (self *imageCache) Update(userId string, image string) string {
	var mimetype string = "image/x-unknown"
	pos := strings.Index(image, ";")
	if pos != -1 {
		mimetype = image[:pos]
		image = image[pos+1:]
	}
	pos = strings.Index(image, ",")
	var decoded []byte
	var err error
	if pos != -1 {
		encoding := image[:pos]
		switch encoding {
		case "base64":
			decoded, err = base64.StdEncoding.DecodeString(image[pos+1:])
			if err != nil {
				return ""
			}
		default:
			log.Println("Unknown encoding", encoding)
			return ""
		}
	} else {
		decoded = []byte(image[pos+1:])
	}
	var img *Image
	self.mutex.RLock()
	result, ok := self.userImages[userId]
	if !ok {
		self.mutex.RUnlock()
		imageId := make([]byte, 16, 16)
		if _, err = rand.Read(imageId); err != nil {
			return ""
		}
		result = base64.URLEncoding.EncodeToString(imageId)
		img = &Image{userid: userId}
		self.mutex.Lock()
		resultTmp, ok := self.userImages[userId]
		if !ok {
			self.userImages[userId] = result
			self.images[result] = img
		} else {
			result = resultTmp
			img = self.images[result]
		}
		self.mutex.Unlock()
	} else {
		img = self.images[result]
		self.mutex.RUnlock()
	}
	if mimetype != img.mimetype || !bytes.Equal(img.data, decoded) {
		img.updateIdx++
		img.mimetype = mimetype
		img.data = decoded
	}
	result += "/" + strconv.Itoa(img.updateIdx)
	filename, ok := imageFilenames[mimetype]
	if ok {
		result += "/" + filename
	}
	return result
}

func (self *imageCache) Get(imageId string) *Image {
	self.mutex.RLock()
	image := self.images[imageId]
	self.mutex.RUnlock()
	return image
}

func (self *imageCache) DeleteUserImage(userId string) {
	self.mutex.Lock()
	imageId, ok := self.userImages[userId]
	if ok {
		delete(self.userImages, userId)
		delete(self.images, imageId)
	}
	self.mutex.Unlock()
}
<commit_msg>Include timestamp of last change in URL instead of human readable update index.<commit_after>package main

import (
	"bytes"
	"crypto/rand"
	"encoding/base64"
	"encoding/binary"
	"log"
	"strings"
	"sync"
	"time"
)

var imageFilenames map[string]string

type Image struct {
	updateIdx    int
	lastChange   time.Time
	lastChangeId string
	userid       string
	mimetype     string
	data         []byte
}

type ImageCache interface {
	Update(userId string, image string) string

	Get(imageId string) *Image

	DeleteUserImage(userId string)
}

type imageCache struct {
	images     map[string]*Image
	userImages map[string]string
	mutex      sync.RWMutex
}

func NewImageCache() ImageCache {
	result := &imageCache{}
	result.images = make(map[string]*Image)
	result.userImages = make(map[string]string)
	if imageFilenames == nil {
		imageFilenames = map[string]string{
			"image/png":  "picture.png",
			"image/jpeg": "picture.jpg",
			"image/gif":  "picture.gif",
		}
	}
	return result
}

func (self *imageCache) Update(userId string, image string) string {
	var mimetype string = "image/x-unknown"
	pos := strings.Index(image, ";")
	if pos != -1 {
		mimetype = image[:pos]
		image = image[pos+1:]
	}
	pos = strings.Index(image, ",")
	var decoded []byte
	var err error
	if pos != -1 {
		encoding := image[:pos]
		switch encoding {
		case "base64":
			decoded, err = base64.StdEncoding.DecodeString(image[pos+1:])
			if err != nil {
				return ""
			}
		default:
			log.Println("Unknown encoding", encoding)
			return ""
		}
	} else {
		decoded = []byte(image[pos+1:])
	}
	var img *Image
	self.mutex.RLock()
	result, ok := self.userImages[userId]
	if !ok {
		self.mutex.RUnlock()
		imageId := make([]byte, 16, 16)
		if _, err = rand.Read(imageId); err != nil {
			return ""
		}
		result = base64.URLEncoding.EncodeToString(imageId)
		img = &Image{userid: userId}
		self.mutex.Lock()
		resultTmp, ok := self.userImages[userId]
		if !ok {
			self.userImages[userId] = result
			self.images[result] = img
		} else {
			result = resultTmp
			img = self.images[result]
		}
		self.mutex.Unlock()
	} else {
		img = self.images[result]
		self.mutex.RUnlock()
	}
	if mimetype != img.mimetype || !bytes.Equal(img.data, decoded) {
		img.updateIdx++
		img.lastChange = time.Now()
		tmp := make([]byte, binary.MaxVarintLen64)
		count := binary.PutUvarint(tmp, uint64(img.lastChange.UnixNano()))
		img.lastChangeId = base64.URLEncoding.EncodeToString(tmp[:count])
		img.mimetype = mimetype
		img.data = decoded
	}
	result += "/" + img.lastChangeId
	filename, ok := imageFilenames[mimetype]
	if ok {
		result += "/" + filename
	}
	return result
}

func (self *imageCache) Get(imageId string) *Image {
	self.mutex.RLock()
	image := self.images[imageId]
	self.mutex.RUnlock()
	return image
}

func (self *imageCache) DeleteUserImage(userId string) {
	self.mutex.Lock()
	imageId, ok := self.userImages[userId]
	if ok {
		delete(self.userImages, userId)
		delete(self.images, imageId)
	}
	self.mutex.Unlock()
}
<|endoftext|>


<commit_before>package legacy

import (
	"fmt"

	"github.com/hashicorp/terraform/backend"
	"github.com/hashicorp/terraform/state"
	"github.com/hashicorp/terraform/state/remote"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/mapstructure"
)

// Backend is an implementation of backend.Backend for legacy remote state
// clients.
type Backend struct {
	// Type is the type of remote state client to support
	Type string

	// client is set after Configure is called and client is initialized.
	client remote.Client
}

func (b *Backend) Input(
	ui terraform.UIInput, c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) {
	// Return the config as-is, legacy doesn't support input
	return c, nil
}

func (b *Backend) Validate(*terraform.ResourceConfig) ([]string, []error) {
	// No validation was supported for old clients
	return nil, nil
}

func (b *Backend) Configure(c *terraform.ResourceConfig) error {
	// Legacy remote state was only map[string]string config
	var conf map[string]string
	if err := mapstructure.Decode(c.Raw, &conf); err != nil {
		return fmt.Errorf(
			"Failed to decode %q configuration: %s\n\n"+
				"This backend expects all configuration keys and values to be\n"+
				"strings. Please verify your configuration and try again.",
			b.Type, err)
	}

	client, err := remote.NewClient(b.Type, conf)
	if err != nil {
		return fmt.Errorf(
			"Failed to configure remote backend %q: %s",
			b.Type, err)
	}

	// Set our client
	b.client = client
	return nil
}

func (b *Backend) State() (state.State, error) {
	if b.client == nil {
		panic("State called with nil remote state client")
	}

	return &remote.State{Client: b.client}, nil
}

func (b *Backend) States() ([]string, string, error) {
	return []string{backend.DefaultStateName}, backend.DefaultStateName, nil
}

func (b *Backend) ChangeState(name string) error {
	return nil
}
<commit_msg>remove some leftover methods in the legacy backend<commit_after>package legacy

import (
	"fmt"

	"github.com/hashicorp/terraform/state"
	"github.com/hashicorp/terraform/state/remote"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/mapstructure"
)

// Backend is an implementation of backend.Backend for legacy remote state
// clients.
type Backend struct {
	// Type is the type of remote state client to support
	Type string

	// client is set after Configure is called and client is initialized.
	client remote.Client
}

func (b *Backend) Input(
	ui terraform.UIInput, c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) {
	// Return the config as-is, legacy doesn't support input
	return c, nil
}

func (b *Backend) Validate(*terraform.ResourceConfig) ([]string, []error) {
	// No validation was supported for old clients
	return nil, nil
}

func (b *Backend) Configure(c *terraform.ResourceConfig) error {
	// Legacy remote state was only map[string]string config
	var conf map[string]string
	if err := mapstructure.Decode(c.Raw, &conf); err != nil {
		return fmt.Errorf(
			"Failed to decode %q configuration: %s\n\n"+
				"This backend expects all configuration keys and values to be\n"+
				"strings. Please verify your configuration and try again.",
			b.Type, err)
	}

	client, err := remote.NewClient(b.Type, conf)
	if err != nil {
		return fmt.Errorf(
			"Failed to configure remote backend %q: %s",
			b.Type, err)
	}

	// Set our client
	b.client = client
	return nil
}

func (b *Backend) State() (state.State, error) {
	if b.client == nil {
		panic("State called with nil remote state client")
	}

	return &remote.State{Client: b.client}, nil
}
<|endoftext|>


<commit_before>package command

import (
	"github.com/mitchellh/cli"
	"github.com/mitchellh/colorstring"
)

// UIOutput is an implementation of terraform.UIOutput.
type UIOutput struct {
	Colorize *colorstring.Colorize
	Ui       cli.Ui
}

func (u *UIOutput) Output(v string) {
}
<commit_msg>command: UIOutput is functinal<commit_after>package command

import (
	"sync"

	"github.com/mitchellh/cli"
	"github.com/mitchellh/colorstring"
)

// UIOutput is an implementation of terraform.UIOutput.
type UIOutput struct {
	Colorize *colorstring.Colorize
	Ui       cli.Ui

	once sync.Once
	ui        cli.Ui
}

func (u *UIOutput) Output(v string) {
	u.once.Do(u.init)
	u.ui.Output(v)
}

func (u *UIOutput) init() {
	// Wrap the ui so that it is safe for concurrency regardless of the
	// underlying reader/writer that is in place.
	u.ui = &cli.ConcurrentUi{Ui: u.Ui}
}
<|endoftext|>


<commit_before>package statsd

import (
	"strings"
	"sync"
	"sync/atomic"
	"time"

	backendTypes "github.com/atlassian/gostatsd/backend/types"
	"github.com/atlassian/gostatsd/types"

	log "github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

// FlusherStats holds statistics about a Flusher.
type FlusherStats struct {
	LastFlush      time.Time // Last time the metrics where aggregated
	LastFlushError time.Time // Time of the last flush error
}

// Flusher periodically flushes metrics from all Aggregators to Senders.
type Flusher interface {
	Run(context.Context) error
	GetStats() FlusherStats
}

type flusher struct {
	// Counter fields below must be read/written only using atomic instructions.
	// 64-bit fields must be the first fields in the struct to guarantee proper memory alignment.
	// See https://golang.org/pkg/sync/atomic/#pkg-note-BUG
	lastFlush      int64 // Last time the metrics where aggregated. Unix timestamp in nsec.
	lastFlushError int64 // Time of the last flush error. Unix timestamp in nsec.

	flushInterval time.Duration // How often to flush metrics to the sender
	dispatcher    Dispatcher
	receiver      Receiver
	defaultTags   string
	backends      []backendTypes.Backend

	// Sent statistics for Receiver. Keep sent values to calculate diff.
	sentBadLines        uint64
	sentPacketsReceived uint64
	sentMetricsReceived uint64
}

// NewFlusher creates a new Flusher with provided configuration.
func NewFlusher(flushInterval time.Duration, dispatcher Dispatcher, receiver Receiver, defaultTags []string, backends []backendTypes.Backend) Flusher {
	return &flusher{
		flushInterval: flushInterval,
		dispatcher:    dispatcher,
		receiver:      receiver,
		defaultTags:   strings.Join(defaultTags, ","),
		backends:      backends,
	}
}

// Run runs the Flusher.
func (f *flusher) Run(ctx context.Context) error {
	flushTimer := time.NewTimer(f.flushInterval)
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-flushTimer.C: // Time to flush to the backends
			f.flushData(ctx)
			flushTimer = time.NewTimer(f.flushInterval)
		}
	}
}

// GetStats returns Flusher statistics.
func (f *flusher) GetStats() FlusherStats {
	return FlusherStats{
		time.Unix(0, atomic.LoadInt64(&f.lastFlush)),
		time.Unix(0, atomic.LoadInt64(&f.lastFlushError)),
	}
}

func (f *flusher) flushData(ctx context.Context) {
	var totalStats uint32
	var sendWg sync.WaitGroup
	processWg := f.dispatcher.Process(ctx, func(aggr Aggregator) {
		aggr.Flush(time.Now)
		aggr.Process(func(m *types.MetricMap) {
			atomic.AddUint32(&totalStats, m.NumStats)
			f.sendMetricsAsync(ctx, &sendWg, m)
		})
		aggr.Reset(time.Now())
	})
	processWg.Wait() // Wait for all workers to execute function
	sendWg.Wait()    // Wait for all backends to finish sending

	f.sendMetricsAsync(ctx, &sendWg, f.internalStats(totalStats))
	sendWg.Wait() // Wait for all backends to finish sending internal metrics
}

func (f *flusher) sendMetricsAsync(ctx context.Context, wg *sync.WaitGroup, m *types.MetricMap) {
	wg.Add(len(f.backends))
	for _, backend := range f.backends {
		log.Debugf("Sending %d metrics to backend %s", m.NumStats, backend.BackendName())
		backend.SendMetricsAsync(ctx, m, func(errs []error) {
			defer wg.Done()
			f.handleSendResult(errs)
		})
	}
}

func (f *flusher) handleSendResult(flushResults []error) {
	timestamp := time.Now().UnixNano()
	if len(flushResults) > 0 {
		for err := range flushResults {
			log.Errorf("Sending metrics to backend failed: %v", err)
		}
		atomic.StoreInt64(&f.lastFlushError, timestamp)
	} else {
		atomic.StoreInt64(&f.lastFlush, timestamp)
	}
}

func (f *flusher) internalStats(totalStats uint32) *types.MetricMap {
	receiverStats := f.receiver.GetStats()
	now := time.Now()
	c := make(types.Counters, 4)
	f.addCounter(c, "bad_lines_seen", now, int64(receiverStats.BadLines-f.sentBadLines))
	f.addCounter(c, "metrics_received", now, int64(receiverStats.MetricsReceived-f.sentMetricsReceived))
	f.addCounter(c, "packets_received", now, int64(receiverStats.PacketsReceived-f.sentPacketsReceived))
	f.addCounter(c, "numStats", now, int64(totalStats))

	log.Debugf("numStats: %d", totalStats)

	f.sentBadLines = receiverStats.BadLines
	f.sentMetricsReceived = receiverStats.MetricsReceived
	f.sentPacketsReceived = receiverStats.PacketsReceived

	return &types.MetricMap{
		NumStats:       4,
		ProcessingTime: time.Duration(0),
		FlushInterval:  f.flushInterval,
		Counters:       c,
	}
}

func (f *flusher) addCounter(c types.Counters, name string, timestamp time.Time, value int64) {
	counter := types.NewCounter(timestamp, f.flushInterval, value)
	counter.PerSecond = float64(counter.Value) / (float64(f.flushInterval) / float64(time.Second))

	elem := make(map[string]types.Counter, 1)
	elem[f.defaultTags] = counter

	c[internalStatName(name)] = elem
}
<commit_msg>Log error not its index<commit_after>package statsd

import (
	"strings"
	"sync"
	"sync/atomic"
	"time"

	backendTypes "github.com/atlassian/gostatsd/backend/types"
	"github.com/atlassian/gostatsd/types"

	log "github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

// FlusherStats holds statistics about a Flusher.
type FlusherStats struct {
	LastFlush      time.Time // Last time the metrics where aggregated
	LastFlushError time.Time // Time of the last flush error
}

// Flusher periodically flushes metrics from all Aggregators to Senders.
type Flusher interface {
	Run(context.Context) error
	GetStats() FlusherStats
}

type flusher struct {
	// Counter fields below must be read/written only using atomic instructions.
	// 64-bit fields must be the first fields in the struct to guarantee proper memory alignment.
	// See https://golang.org/pkg/sync/atomic/#pkg-note-BUG
	lastFlush      int64 // Last time the metrics where aggregated. Unix timestamp in nsec.
	lastFlushError int64 // Time of the last flush error. Unix timestamp in nsec.

	flushInterval time.Duration // How often to flush metrics to the sender
	dispatcher    Dispatcher
	receiver      Receiver
	defaultTags   string
	backends      []backendTypes.Backend

	// Sent statistics for Receiver. Keep sent values to calculate diff.
	sentBadLines        uint64
	sentPacketsReceived uint64
	sentMetricsReceived uint64
}

// NewFlusher creates a new Flusher with provided configuration.
func NewFlusher(flushInterval time.Duration, dispatcher Dispatcher, receiver Receiver, defaultTags []string, backends []backendTypes.Backend) Flusher {
	return &flusher{
		flushInterval: flushInterval,
		dispatcher:    dispatcher,
		receiver:      receiver,
		defaultTags:   strings.Join(defaultTags, ","),
		backends:      backends,
	}
}

// Run runs the Flusher.
func (f *flusher) Run(ctx context.Context) error {
	flushTimer := time.NewTimer(f.flushInterval)
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-flushTimer.C: // Time to flush to the backends
			f.flushData(ctx)
			flushTimer = time.NewTimer(f.flushInterval)
		}
	}
}

// GetStats returns Flusher statistics.
func (f *flusher) GetStats() FlusherStats {
	return FlusherStats{
		time.Unix(0, atomic.LoadInt64(&f.lastFlush)),
		time.Unix(0, atomic.LoadInt64(&f.lastFlushError)),
	}
}

func (f *flusher) flushData(ctx context.Context) {
	var totalStats uint32
	var sendWg sync.WaitGroup
	processWg := f.dispatcher.Process(ctx, func(aggr Aggregator) {
		aggr.Flush(time.Now)
		aggr.Process(func(m *types.MetricMap) {
			atomic.AddUint32(&totalStats, m.NumStats)
			f.sendMetricsAsync(ctx, &sendWg, m)
		})
		aggr.Reset(time.Now())
	})
	processWg.Wait() // Wait for all workers to execute function
	sendWg.Wait()    // Wait for all backends to finish sending

	f.sendMetricsAsync(ctx, &sendWg, f.internalStats(totalStats))
	sendWg.Wait() // Wait for all backends to finish sending internal metrics
}

func (f *flusher) sendMetricsAsync(ctx context.Context, wg *sync.WaitGroup, m *types.MetricMap) {
	wg.Add(len(f.backends))
	for _, backend := range f.backends {
		log.Debugf("Sending %d metrics to backend %s", m.NumStats, backend.BackendName())
		backend.SendMetricsAsync(ctx, m, func(errs []error) {
			defer wg.Done()
			f.handleSendResult(errs)
		})
	}
}

func (f *flusher) handleSendResult(flushResults []error) {
	timestamp := time.Now().UnixNano()
	if len(flushResults) > 0 {
		for _, err := range flushResults {
			log.Errorf("Sending metrics to backend failed: %v", err)
		}
		atomic.StoreInt64(&f.lastFlushError, timestamp)
	} else {
		atomic.StoreInt64(&f.lastFlush, timestamp)
	}
}

func (f *flusher) internalStats(totalStats uint32) *types.MetricMap {
	receiverStats := f.receiver.GetStats()
	now := time.Now()
	c := make(types.Counters, 4)
	f.addCounter(c, "bad_lines_seen", now, int64(receiverStats.BadLines-f.sentBadLines))
	f.addCounter(c, "metrics_received", now, int64(receiverStats.MetricsReceived-f.sentMetricsReceived))
	f.addCounter(c, "packets_received", now, int64(receiverStats.PacketsReceived-f.sentPacketsReceived))
	f.addCounter(c, "numStats", now, int64(totalStats))

	log.Debugf("numStats: %d", totalStats)

	f.sentBadLines = receiverStats.BadLines
	f.sentMetricsReceived = receiverStats.MetricsReceived
	f.sentPacketsReceived = receiverStats.PacketsReceived

	return &types.MetricMap{
		NumStats:       4,
		ProcessingTime: time.Duration(0),
		FlushInterval:  f.flushInterval,
		Counters:       c,
	}
}

func (f *flusher) addCounter(c types.Counters, name string, timestamp time.Time, value int64) {
	counter := types.NewCounter(timestamp, f.flushInterval, value)
	counter.PerSecond = float64(counter.Value) / (float64(f.flushInterval) / float64(time.Second))

	elem := make(map[string]types.Counter, 1)
	elem[f.defaultTags] = counter

	c[internalStatName(name)] = elem
}
<|endoftext|>