<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"
)

type (
	// Daemon defines Docker daemon parameters.
	Daemon struct {
		Registry      string   // Docker registry
		Mirror        string   // Docker registry mirror
		Insecure      bool     // Docker daemon enable insecure registries
		StorageDriver string   // Docker daemon storage driver
		StoragePath   string   // Docker daemon storage path
		Disabled      bool     // DOcker daemon is disabled (already running)
		Debug         bool     // Docker daemon started in debug mode
		Bip           string   // Docker daemon network bridge IP address
		DNS           []string // Docker daemon dns server
	}

	// Login defines Docker login parameters.
	Login struct {
		Registry string // Docker registry address
		Username string // Docker registry username
		Password string // Docker registry password
		Email    string // Docker registry email
	}

	// Build defines Docker build parameters.
	Build struct {
		Name       string   // Docker build using default named tag
		Dockerfile string   // Docker build Dockerfile
		Context    string   // Docker build context
		Tags       []string // Docker build tags
		Args       []string // Docker build args
		Repo       string   // Docker build repository
	}

	// Plugin defines the Docker plugin parameters.
	Plugin struct {
		Login  Login  // Docker login configuration
		Build  Build  // Docker build configuration
		Daemon Daemon // Docker daemon configuration
		Dryrun bool   // Docker push is skipped
	}
)

// Exec executes the plugin step
func (p Plugin) Exec() error {

	// start the Docker daemon server
	if !p.Daemon.Disabled {
		cmd := commandDaemon(p.Daemon)
		if p.Daemon.Debug {
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
		} else {
			cmd.Stdout = ioutil.Discard
			cmd.Stderr = ioutil.Discard
		}
		go func() {
			trace(cmd)
			cmd.Run()
		}()
	}

	// poll the docker daemon until it is started. This ensures the daemon is
	// ready to accept connections before we proceed.
	for i := 0; i < 15; i++ {
		cmd := commandInfo()
		err := cmd.Run()
		if err == nil {
			break
		}
		time.Sleep(time.Second * 1)
	}

	// login to the Docker registry
	if p.Login.Password != "" {
		cmd := commandLogin(p.Login)
		err := cmd.Run()
		if err != nil {
			return fmt.Errorf("Error authenticating: %s", err)
		}
	} else {
		fmt.Println("Registry credentials not provided. Guest mode enabled.")
	}

	var cmds []*exec.Cmd
	cmds = append(cmds, commandVersion())      // docker version
	cmds = append(cmds, commandInfo())         // docker info
	cmds = append(cmds, commandBuild(p.Build)) // docker build

	for _, tag := range p.Build.Tags {
		cmds = append(cmds, commandTag(p.Build, tag)) // docker tag

		if p.Dryrun == false {
			cmds = append(cmds, commandPush(p.Build, tag)) // docker push
		}
	}

	// execute all commands in batch mode.
	for _, cmd := range cmds {
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		trace(cmd)

		err := cmd.Run()
		if err != nil {
			return err
		}
	}

	return nil
}

const dockerExe = "/usr/local/bin/docker"

// helper function to create the docker login command.
func commandLogin(login Login) *exec.Cmd {
	if p.Login.Email != "" {
		return commandLoginEmail(p.Login)
	}
	return exec.Command(
		dockerExe, "login",
		"-u", login.Username,
		"-p", login.Password,
		login.Registry,
	)
}

func commandLoginEmail(p.Login) *exec.Cmd {
	return exec.Command(
		dockerExe, "login",
		"-u", login.Username,
		"-p", login.Password,
		"-e", login.Email,
		login.Registry,
	)
}

// helper function to create the docker info command.
func commandVersion() *exec.Cmd {
	return exec.Command(dockerExe, "version")
}

// helper function to create the docker info command.
func commandInfo() *exec.Cmd {
	return exec.Command(dockerExe, "info")
}

// helper function to create the docker build command.
func commandBuild(build Build) *exec.Cmd {
	cmd := exec.Command(
		dockerExe, "build",
		"--pull=true",
		"--rm=true",
		"-f", build.Dockerfile,
		"-t", build.Name,
	)
	for _, arg := range build.Args {
		cmd.Args = append(cmd.Args, "--build-arg", arg)
	}
	cmd.Args = append(cmd.Args, build.Context)
	return cmd
}

// helper function to create the docker tag command.
func commandTag(build Build, tag string) *exec.Cmd {
	var (
		source = build.Name
		target = fmt.Sprintf("%s:%s", build.Repo, tag)
	)
	return exec.Command(
		dockerExe, "tag", source, target,
	)
}

// helper function to create the docker push command.
func commandPush(build Build, tag string) *exec.Cmd {
	target := fmt.Sprintf("%s:%s", build.Repo, tag)
	return exec.Command(dockerExe, "push", target)
}

// helper function to create the docker daemon command.
func commandDaemon(daemon Daemon) *exec.Cmd {
	args := []string{"daemon", "-g", daemon.StoragePath}

	if daemon.StorageDriver != "" {
		args = append(args, "-s", daemon.StorageDriver)
	}
	if daemon.Insecure && daemon.Registry != "" {
		args = append(args, "--insecure-registry", daemon.Registry)
	}
	if len(daemon.Mirror) != 0 {
		args = append(args, "--registry-mirror", daemon.Mirror)
	}
	if len(daemon.Bip) != 0 {
		args = append(args, "--bip", daemon.Bip)
	}
	for _, dns := range daemon.DNS {
		args = append(args, "--dns", dns)
	}
	return exec.Command(dockerExe, args...)
}

// trace writes each command to stdout with the command wrapped in an xml
// tag so that it can be extracted and displayed in the logs.
func trace(cmd *exec.Cmd) {
	fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " "))
}
<commit_msg>Fix argument type<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"
)

type (
	// Daemon defines Docker daemon parameters.
	Daemon struct {
		Registry      string   // Docker registry
		Mirror        string   // Docker registry mirror
		Insecure      bool     // Docker daemon enable insecure registries
		StorageDriver string   // Docker daemon storage driver
		StoragePath   string   // Docker daemon storage path
		Disabled      bool     // DOcker daemon is disabled (already running)
		Debug         bool     // Docker daemon started in debug mode
		Bip           string   // Docker daemon network bridge IP address
		DNS           []string // Docker daemon dns server
	}

	// Login defines Docker login parameters.
	Login struct {
		Registry string // Docker registry address
		Username string // Docker registry username
		Password string // Docker registry password
		Email    string // Docker registry email
	}

	// Build defines Docker build parameters.
	Build struct {
		Name       string   // Docker build using default named tag
		Dockerfile string   // Docker build Dockerfile
		Context    string   // Docker build context
		Tags       []string // Docker build tags
		Args       []string // Docker build args
		Repo       string   // Docker build repository
	}

	// Plugin defines the Docker plugin parameters.
	Plugin struct {
		Login  Login  // Docker login configuration
		Build  Build  // Docker build configuration
		Daemon Daemon // Docker daemon configuration
		Dryrun bool   // Docker push is skipped
	}
)

// Exec executes the plugin step
func (p Plugin) Exec() error {

	// start the Docker daemon server
	if !p.Daemon.Disabled {
		cmd := commandDaemon(p.Daemon)
		if p.Daemon.Debug {
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
		} else {
			cmd.Stdout = ioutil.Discard
			cmd.Stderr = ioutil.Discard
		}
		go func() {
			trace(cmd)
			cmd.Run()
		}()
	}

	// poll the docker daemon until it is started. This ensures the daemon is
	// ready to accept connections before we proceed.
	for i := 0; i < 15; i++ {
		cmd := commandInfo()
		err := cmd.Run()
		if err == nil {
			break
		}
		time.Sleep(time.Second * 1)
	}

	// login to the Docker registry
	if p.Login.Password != "" {
		cmd := commandLogin(p.Login)
		err := cmd.Run()
		if err != nil {
			return fmt.Errorf("Error authenticating: %s", err)
		}
	} else {
		fmt.Println("Registry credentials not provided. Guest mode enabled.")
	}

	var cmds []*exec.Cmd
	cmds = append(cmds, commandVersion())      // docker version
	cmds = append(cmds, commandInfo())         // docker info
	cmds = append(cmds, commandBuild(p.Build)) // docker build

	for _, tag := range p.Build.Tags {
		cmds = append(cmds, commandTag(p.Build, tag)) // docker tag

		if p.Dryrun == false {
			cmds = append(cmds, commandPush(p.Build, tag)) // docker push
		}
	}

	// execute all commands in batch mode.
	for _, cmd := range cmds {
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		trace(cmd)

		err := cmd.Run()
		if err != nil {
			return err
		}
	}

	return nil
}

const dockerExe = "/usr/local/bin/docker"

// helper function to create the docker login command.
func commandLogin(login Login) *exec.Cmd {
	if p.Login.Email != "" {
		return commandLoginEmail(p.Login)
	}
	return exec.Command(
		dockerExe, "login",
		"-u", login.Username,
		"-p", login.Password,
		login.Registry,
	)
}

func commandLoginEmail(login Login) *exec.Cmd {
	return exec.Command(
		dockerExe, "login",
		"-u", login.Username,
		"-p", login.Password,
		"-e", login.Email,
		login.Registry,
	)
}

// helper function to create the docker info command.
func commandVersion() *exec.Cmd {
	return exec.Command(dockerExe, "version")
}

// helper function to create the docker info command.
func commandInfo() *exec.Cmd {
	return exec.Command(dockerExe, "info")
}

// helper function to create the docker build command.
func commandBuild(build Build) *exec.Cmd {
	cmd := exec.Command(
		dockerExe, "build",
		"--pull=true",
		"--rm=true",
		"-f", build.Dockerfile,
		"-t", build.Name,
	)
	for _, arg := range build.Args {
		cmd.Args = append(cmd.Args, "--build-arg", arg)
	}
	cmd.Args = append(cmd.Args, build.Context)
	return cmd
}

// helper function to create the docker tag command.
func commandTag(build Build, tag string) *exec.Cmd {
	var (
		source = build.Name
		target = fmt.Sprintf("%s:%s", build.Repo, tag)
	)
	return exec.Command(
		dockerExe, "tag", source, target,
	)
}

// helper function to create the docker push command.
func commandPush(build Build, tag string) *exec.Cmd {
	target := fmt.Sprintf("%s:%s", build.Repo, tag)
	return exec.Command(dockerExe, "push", target)
}

// helper function to create the docker daemon command.
func commandDaemon(daemon Daemon) *exec.Cmd {
	args := []string{"daemon", "-g", daemon.StoragePath}

	if daemon.StorageDriver != "" {
		args = append(args, "-s", daemon.StorageDriver)
	}
	if daemon.Insecure && daemon.Registry != "" {
		args = append(args, "--insecure-registry", daemon.Registry)
	}
	if len(daemon.Mirror) != 0 {
		args = append(args, "--registry-mirror", daemon.Mirror)
	}
	if len(daemon.Bip) != 0 {
		args = append(args, "--bip", daemon.Bip)
	}
	for _, dns := range daemon.DNS {
		args = append(args, "--dns", dns)
	}
	return exec.Command(dockerExe, args...)
}

// trace writes each command to stdout with the command wrapped in an xml
// tag so that it can be extracted and displayed in the logs.
func trace(cmd *exec.Cmd) {
	fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " "))
}
<|endoftext|>


<commit_before>package main

import (
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/docker/swarm/api"
	"github.com/docker/swarm/cluster"
	"github.com/docker/swarm/discovery"
	"github.com/docker/swarm/scheduler"
	"github.com/docker/swarm/scheduler/filter"
	"github.com/docker/swarm/scheduler/strategy"
)

type logHandler struct {
}

func (h *logHandler) Handle(e *cluster.Event) error {
	log.Printf("event -> type: %q time: %q image: %q container: %q", e.Type, e.Time.Format(time.RubyDate), e.Container.Image, e.Container.Id)
	return nil
}

func manage(c *cli.Context) {

	refresh := func(c *cluster.Cluster, nodes []string) error {
		for _, addr := range nodes {
			if !strings.Contains(addr, "://") {
				addr = "http://" + addr
			}
			if c.Node(addr) == nil {
				n := cluster.NewNode(addr)
				if err := n.Connect(nil); err != nil {
					return err
				}
				if err := c.AddNode(n); err != nil {
					return err
				}
			}
		}
		return nil
	}

	cluster := cluster.NewCluster()
	cluster.Events(&logHandler{})

	go func() {
		if c.String("token") != "" {
			nodes, err := discovery.FetchSlaves(c.String("token"))
			if err != nil {
				log.Fatal(err)

			}
			if err := refresh(cluster, nodes); err != nil {
				log.Fatal(err)
			}
			hb := time.Duration(c.Int("heartbeat"))
			go func() {
				for {
					time.Sleep(hb * time.Second)
					nodes, err = discovery.FetchSlaves(c.String("token"))
					if err == nil {
						refresh(cluster, nodes)
					}
				}
			}()
		} else {
			if err := refresh(cluster, c.Args()); err != nil {
				log.Fatal(err)
			}
		}
	}()

	s := scheduler.NewScheduler(cluster, &strategy.BinPackingPlacementStrategy{}, []filter.Filter{&filter.AttributeFilter{}, &filter.PortFilter{}})

	log.Fatal(api.ListenAndServe(cluster, s, c.String("addr")))
}
<commit_msg>manage cluster: Set a default overcommit ratio of 5%.<commit_after>package main

import (
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/docker/swarm/api"
	"github.com/docker/swarm/cluster"
	"github.com/docker/swarm/discovery"
	"github.com/docker/swarm/scheduler"
	"github.com/docker/swarm/scheduler/filter"
	"github.com/docker/swarm/scheduler/strategy"
)

type logHandler struct {
}

func (h *logHandler) Handle(e *cluster.Event) error {
	log.Printf("event -> type: %q time: %q image: %q container: %q", e.Type, e.Time.Format(time.RubyDate), e.Container.Image, e.Container.Id)
	return nil
}

func manage(c *cli.Context) {

	refresh := func(c *cluster.Cluster, nodes []string) error {
		for _, addr := range nodes {
			if !strings.Contains(addr, "://") {
				addr = "http://" + addr
			}
			if c.Node(addr) == nil {
				n := cluster.NewNode(addr)
				if err := n.Connect(nil); err != nil {
					return err
				}
				if err := c.AddNode(n); err != nil {
					return err
				}
			}
		}
		return nil
	}

	cluster := cluster.NewCluster()
	cluster.Events(&logHandler{})

	go func() {
		if c.String("token") != "" {
			nodes, err := discovery.FetchSlaves(c.String("token"))
			if err != nil {
				log.Fatal(err)

			}
			if err := refresh(cluster, nodes); err != nil {
				log.Fatal(err)
			}
			hb := time.Duration(c.Int("heartbeat"))
			go func() {
				for {
					time.Sleep(hb * time.Second)
					nodes, err = discovery.FetchSlaves(c.String("token"))
					if err == nil {
						refresh(cluster, nodes)
					}
				}
			}()
		} else {
			if err := refresh(cluster, c.Args()); err != nil {
				log.Fatal(err)
			}
		}
	}()

	s := scheduler.NewScheduler(
		cluster,
		&strategy.BinPackingPlacementStrategy{OvercommitRatio: 0.05},
		[]filter.Filter{&filter.AttributeFilter{}, &filter.PortFilter{}},
	)

	log.Fatal(api.ListenAndServe(cluster, s, c.String("addr")))
}
<|endoftext|>


<commit_before>package common

import (
	"io"
	"regexp"
)

type UpdateState int
type UploadState int
type DownloadState int

const (
	UpdateSucceeded UpdateState = iota
	UpdateNotFound
	UpdateAbort
	UpdateFailed
	UpdateRangeMissmatch
)

const (
	UploadSucceeded UploadState = iota
	UploadTooLarge
	UploadForbidden
	UploadFailed
)

const (
	DownloadSucceeded DownloadState = iota
	DownloadForbidden
	DownloadFailed
	DownloadNotFound
)

type FeaturesInfo struct {
	Variables bool `json:"variables"`
	Image     bool `json:"image"`
	Services  bool `json:"services"`
	Artifacts bool `json:"features"`
	Cache     bool `json:"cache"`
}

type VersionInfo struct {
	Name         string       `json:"name,omitempty"`
	Version      string       `json:"version,omitempty"`
	Revision     string       `json:"revision,omitempty"`
	Platform     string       `json:"platform,omitempty"`
	Architecture string       `json:"architecture,omitempty"`
	Executor     string       `json:"executor,omitempty"`
	Features     FeaturesInfo `json:"features"`
}

type GetBuildRequest struct {
	Info  VersionInfo `json:"info,omitempty"`
	Token string      `json:"token,omitempty"`
}

type BuildArtifacts struct {
	Filename string `json:"filename,omitempty"`
	Size     int64  `json:"size,omitempty"`
}

type BuildInfo struct {
	ID        int             `json:"id,omitempty"`
	Sha       string          `json:"sha,omitempty"`
	RefName   string          `json:"ref,omitempty"`
	Token     string          `json:"token"`
	Name      string          `json:"name"`
	Stage     string          `json:"stage"`
	Tag       bool            `json:"tag"`
	Artifacts *BuildArtifacts `json:"artifacts_file"`
}

type GetBuildResponse struct {
	ID              int            `json:"id,omitempty"`
	ProjectID       int            `json:"project_id,omitempty"`
	Commands        string         `json:"commands,omitempty"`
	RepoURL         string         `json:"repo_url,omitempty"`
	Sha             string         `json:"sha,omitempty"`
	RefName         string         `json:"ref,omitempty"`
	BeforeSha       string         `json:"before_sha,omitempty"`
	AllowGitFetch   bool           `json:"allow_git_fetch,omitempty"`
	Timeout         int            `json:"timeout,omitempty"`
	Variables       BuildVariables `json:"variables"`
	Options         BuildOptions   `json:"options"`
	Token           string         `json:"token"`
	Name            string         `json:"name"`
	Stage           string         `json:"stage"`
	Tag             bool           `json:"tag"`
	DependsOnBuilds []BuildInfo    `json:"depends_on_builds"`
	TLSCAChain      string         `json:"-"`
}

func (b *GetBuildResponse) RepoCleanURL() string {
	reg, err := regexp.Compile("gitlab-ci-token:[^@]+@")
	if err != nil {
		return ""
	}

	return reg.ReplaceAllString(b.RepoURL, "")
}

type RegisterRunnerRequest struct {
	Info        VersionInfo `json:"info,omitempty"`
	Token       string      `json:"token,omitempty"`
	Description string      `json:"description,omitempty"`
	Tags        string      `json:"tag_list,omitempty"`
}

type RegisterRunnerResponse struct {
	Token string `json:"token,omitempty"`
}

type DeleteRunnerRequest struct {
	Token string `json:"token,omitempty"`
}

type VerifyRunnerRequest struct {
	Token string `json:"token,omitempty"`
}

type UpdateBuildRequest struct {
	Info  VersionInfo `json:"info,omitempty"`
	Token string      `json:"token,omitempty"`
	State BuildState  `json:"state,omitempty"`
	Trace *string     `json:"trace,omitempty"`
}

type BuildCredentials struct {
	ID        int    `long:"id" env:"CI_BUILD_ID" description:"The build ID to upload artifacts for"`
	Token     string `long:"token" env:"CI_BUILD_TOKEN" required:"true" description:"Build token"`
	URL       string `long:"url" env:"CI_SERVER_URL" required:"true" description:"GitLab CI URL"`
	TLSCAFile string `long:"tls-ca-file" env:"CI_SERVER_TLS_CA_FILE" description:"File containing the certificates to verify the peer when using HTTPS"`
}

type BuildTrace interface {
	io.Writer
	Success()
	Fail(err error)
	Aborted() chan interface{}
	IsStdout() bool
}

type BuildTracePatch interface {
	Patch() []byte
	Offset() int
	Limit() int
	SetNewOffset(newOffset int)
}

type Network interface {
	GetBuild(config RunnerConfig) (*GetBuildResponse, bool)
	RegisterRunner(config RunnerCredentials, description, tags string) *RegisterRunnerResponse
	DeleteRunner(config RunnerCredentials) bool
	VerifyRunner(config RunnerCredentials) bool
	UpdateBuild(config RunnerConfig, id int, state BuildState, trace *string) UpdateState
	PatchTrace(config RunnerConfig, buildCredentials *BuildCredentials, tracePart BuildTracePatch) UpdateState
	DownloadArtifacts(config BuildCredentials, artifactsFile string) DownloadState
	UploadRawArtifacts(config BuildCredentials, reader io.Reader, baseName string, expireIn string) UploadState
	UploadArtifacts(config BuildCredentials, artifactsFile string) UploadState
	ProcessBuild(config RunnerConfig, buildCredentials *BuildCredentials) BuildTrace
}
<commit_msg>Change regexp to uri.Parse for cleaning repoURL<commit_after>package common

import (
	"io"
	"net/url"
)

type UpdateState int
type UploadState int
type DownloadState int

const (
	UpdateSucceeded UpdateState = iota
	UpdateNotFound
	UpdateAbort
	UpdateFailed
	UpdateRangeMissmatch
)

const (
	UploadSucceeded UploadState = iota
	UploadTooLarge
	UploadForbidden
	UploadFailed
)

const (
	DownloadSucceeded DownloadState = iota
	DownloadForbidden
	DownloadFailed
	DownloadNotFound
)

type FeaturesInfo struct {
	Variables bool `json:"variables"`
	Image     bool `json:"image"`
	Services  bool `json:"services"`
	Artifacts bool `json:"features"`
	Cache     bool `json:"cache"`
}

type VersionInfo struct {
	Name         string       `json:"name,omitempty"`
	Version      string       `json:"version,omitempty"`
	Revision     string       `json:"revision,omitempty"`
	Platform     string       `json:"platform,omitempty"`
	Architecture string       `json:"architecture,omitempty"`
	Executor     string       `json:"executor,omitempty"`
	Features     FeaturesInfo `json:"features"`
}

type GetBuildRequest struct {
	Info  VersionInfo `json:"info,omitempty"`
	Token string      `json:"token,omitempty"`
}

type BuildArtifacts struct {
	Filename string `json:"filename,omitempty"`
	Size     int64  `json:"size,omitempty"`
}

type BuildInfo struct {
	ID        int             `json:"id,omitempty"`
	Sha       string          `json:"sha,omitempty"`
	RefName   string          `json:"ref,omitempty"`
	Token     string          `json:"token"`
	Name      string          `json:"name"`
	Stage     string          `json:"stage"`
	Tag       bool            `json:"tag"`
	Artifacts *BuildArtifacts `json:"artifacts_file"`
}

type GetBuildResponse struct {
	ID              int            `json:"id,omitempty"`
	ProjectID       int            `json:"project_id,omitempty"`
	Commands        string         `json:"commands,omitempty"`
	RepoURL         string         `json:"repo_url,omitempty"`
	Sha             string         `json:"sha,omitempty"`
	RefName         string         `json:"ref,omitempty"`
	BeforeSha       string         `json:"before_sha,omitempty"`
	AllowGitFetch   bool           `json:"allow_git_fetch,omitempty"`
	Timeout         int            `json:"timeout,omitempty"`
	Variables       BuildVariables `json:"variables"`
	Options         BuildOptions   `json:"options"`
	Token           string         `json:"token"`
	Name            string         `json:"name"`
	Stage           string         `json:"stage"`
	Tag             bool           `json:"tag"`
	DependsOnBuilds []BuildInfo    `json:"depends_on_builds"`
	TLSCAChain      string         `json:"-"`
}

func (b *GetBuildResponse) RepoCleanURL() string {
	repoURL, err := url.Parse(b.RepoURL)
	if err != nil {
		return err.Error()
	}

	repoURL.User = nil
	return repoURL.String()
}

type RegisterRunnerRequest struct {
	Info        VersionInfo `json:"info,omitempty"`
	Token       string      `json:"token,omitempty"`
	Description string      `json:"description,omitempty"`
	Tags        string      `json:"tag_list,omitempty"`
}

type RegisterRunnerResponse struct {
	Token string `json:"token,omitempty"`
}

type DeleteRunnerRequest struct {
	Token string `json:"token,omitempty"`
}

type VerifyRunnerRequest struct {
	Token string `json:"token,omitempty"`
}

type UpdateBuildRequest struct {
	Info  VersionInfo `json:"info,omitempty"`
	Token string      `json:"token,omitempty"`
	State BuildState  `json:"state,omitempty"`
	Trace *string     `json:"trace,omitempty"`
}

type BuildCredentials struct {
	ID        int    `long:"id" env:"CI_BUILD_ID" description:"The build ID to upload artifacts for"`
	Token     string `long:"token" env:"CI_BUILD_TOKEN" required:"true" description:"Build token"`
	URL       string `long:"url" env:"CI_SERVER_URL" required:"true" description:"GitLab CI URL"`
	TLSCAFile string `long:"tls-ca-file" env:"CI_SERVER_TLS_CA_FILE" description:"File containing the certificates to verify the peer when using HTTPS"`
}

type BuildTrace interface {
	io.Writer
	Success()
	Fail(err error)
	Aborted() chan interface{}
	IsStdout() bool
}

type BuildTracePatch interface {
	Patch() []byte
	Offset() int
	Limit() int
	SetNewOffset(newOffset int)
}

type Network interface {
	GetBuild(config RunnerConfig) (*GetBuildResponse, bool)
	RegisterRunner(config RunnerCredentials, description, tags string) *RegisterRunnerResponse
	DeleteRunner(config RunnerCredentials) bool
	VerifyRunner(config RunnerCredentials) bool
	UpdateBuild(config RunnerConfig, id int, state BuildState, trace *string) UpdateState
	PatchTrace(config RunnerConfig, buildCredentials *BuildCredentials, tracePart BuildTracePatch) UpdateState
	DownloadArtifacts(config BuildCredentials, artifactsFile string) DownloadState
	UploadRawArtifacts(config BuildCredentials, reader io.Reader, baseName string, expireIn string) UploadState
	UploadArtifacts(config BuildCredentials, artifactsFile string) UploadState
	ProcessBuild(config RunnerConfig, buildCredentials *BuildCredentials) BuildTrace
}
<|endoftext|>


<commit_before>/*
Copyright 2018 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.
*/

// TODO: We did some scalability tests and using watchBasedManager
// seems to help with apiserver performance at scale visibly.
// No issues we also observed at the scale of ~200k watchers with a
// single apiserver.
// However, we need to perform more extensive testing before we
// enable this in production setups.

package manager

import (
	"fmt"
	"sync"
	"time"

	"k8s.io/api/core/v1"
	"k8s.io/client-go/tools/cache"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apimachinery/pkg/watch"
)

type listObjectFunc func(string, metav1.ListOptions) (runtime.Object, error)
type watchObjectFunc func(string, metav1.ListOptions) (watch.Interface, error)
type newObjectFunc func() runtime.Object

// objectCacheItem is a single item stored in objectCache.
type objectCacheItem struct {
	refCount  int
	store     cache.Store
	hasSynced func() (bool, error)
	stopCh    chan struct{}
}

// objectCache is a local cache of objects propagated via
// individual watches.
type objectCache struct {
	listObject    listObjectFunc
	watchObject   watchObjectFunc
	newObject     newObjectFunc
	groupResource schema.GroupResource

	lock  sync.Mutex
	items map[objectKey]*objectCacheItem
}

// NewObjectCache returns a new watch-based instance of Store interface.
func NewObjectCache(listObject listObjectFunc, watchObject watchObjectFunc, newObject newObjectFunc, groupResource schema.GroupResource) Store {
	return &objectCache{
		listObject:    listObject,
		watchObject:   watchObject,
		newObject:     newObject,
		groupResource: groupResource,
		items:         make(map[objectKey]*objectCacheItem),
	}
}

func (c *objectCache) newStore() cache.Store {
	// TODO: We may consider created a dedicated store keeping just a single
	// item, instead of using a generic store implementation for this purpose.
	// However, simple benchmarks show that memory overhead in that case is
	// decrease from ~600B to ~300B per object. So we are not optimizing it
	// until we will see a good reason for that.
	return cache.NewStore(cache.MetaNamespaceKeyFunc)
}

func (c *objectCache) newReflector(namespace, name string) *objectCacheItem {
	fieldSelector := fields.Set{"metadata.name": name}.AsSelector().String()
	listFunc := func(options metav1.ListOptions) (runtime.Object, error) {
		options.FieldSelector = fieldSelector
		return c.listObject(namespace, options)
	}
	watchFunc := func(options metav1.ListOptions) (watch.Interface, error) {
		options.FieldSelector = fieldSelector
		return c.watchObject(namespace, options)
	}
	store := c.newStore()
	reflector := cache.NewNamedReflector(
		fmt.Sprintf("object-%q/%q", namespace, name),
		&cache.ListWatch{ListFunc: listFunc, WatchFunc: watchFunc},
		c.newObject(),
		store,
		0,
	)
	stopCh := make(chan struct{})
	go reflector.Run(stopCh)
	return &objectCacheItem{
		refCount:  0,
		store:     store,
		hasSynced: func() (bool, error) { return reflector.LastSyncResourceVersion() != "", nil },
		stopCh:    stopCh,
	}
}

func (c *objectCache) AddReference(namespace, name string) {
	key := objectKey{namespace: namespace, name: name}

	// AddReference is called from RegisterPod thus it needs to be efficient.
	// Thus, it is only increaisng refCount and in case of first registration
	// of a given object it starts corresponding reflector.
	// It's responsibility of the first Get operation to wait until the
	// reflector propagated the store.
	c.lock.Lock()
	defer c.lock.Unlock()
	item, exists := c.items[key]
	if !exists {
		item = c.newReflector(namespace, name)
		c.items[key] = item
	}
	item.refCount++
}

func (c *objectCache) DeleteReference(namespace, name string) {
	key := objectKey{namespace: namespace, name: name}

	c.lock.Lock()
	defer c.lock.Unlock()
	if item, ok := c.items[key]; ok {
		item.refCount--
		if item.refCount == 0 {
			// Stop the underlying reflector.
			close(item.stopCh)
			delete(c.items, key)
		}
	}
}

// key returns key of an object with a given name and namespace.
// This has to be in-sync with cache.MetaNamespaceKeyFunc.
func (c *objectCache) key(namespace, name string) string {
	if len(namespace) > 0 {
		return namespace + "/" + name
	}
	return name
}

func (c *objectCache) Get(namespace, name string) (runtime.Object, error) {
	key := objectKey{namespace: namespace, name: name}

	c.lock.Lock()
	item, exists := c.items[key]
	c.lock.Unlock()

	if !exists {
		return nil, fmt.Errorf("object %q/%q not registered", namespace, name)
	}
	if err := wait.PollImmediate(10*time.Millisecond, time.Second, item.hasSynced); err != nil {
		return nil, fmt.Errorf("couldn't propagate object cache: %v", err)
	}

	obj, exists, err := item.store.GetByKey(c.key(namespace, name))
	if err != nil {
		return nil, err
	}
	if !exists {
		return nil, apierrors.NewNotFound(c.groupResource, name)
	}
	if object, ok := obj.(runtime.Object); ok {
		return object, nil
	}
	return nil, fmt.Errorf("unexpected object type: %v", obj)
}

// NewWatchBasedManager creates a manager that keeps a cache of all objects
// necessary for registered pods.
// It implements the following logic:
// - whenever a pod is created or updated, we start individual watches for all
//   referenced objects that aren't referenced from other registered pods
// - every GetObject() returns a value from local cache propagated via watches
func NewWatchBasedManager(listObject listObjectFunc, watchObject watchObjectFunc, newObject newObjectFunc, groupResource schema.GroupResource, getReferencedObjects func(*v1.Pod) sets.String) Manager {
	objectStore := NewObjectCache(listObject, watchObject, newObject, groupResource)
	return NewCacheBasedManager(objectStore, getReferencedObjects)
}
<commit_msg>Fix message of failed sync<commit_after>/*
Copyright 2018 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.
*/

// TODO: We did some scalability tests and using watchBasedManager
// seems to help with apiserver performance at scale visibly.
// No issues we also observed at the scale of ~200k watchers with a
// single apiserver.
// However, we need to perform more extensive testing before we
// enable this in production setups.

package manager

import (
	"fmt"
	"sync"
	"time"

	"k8s.io/api/core/v1"
	"k8s.io/client-go/tools/cache"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apimachinery/pkg/watch"
)

type listObjectFunc func(string, metav1.ListOptions) (runtime.Object, error)
type watchObjectFunc func(string, metav1.ListOptions) (watch.Interface, error)
type newObjectFunc func() runtime.Object

// objectCacheItem is a single item stored in objectCache.
type objectCacheItem struct {
	refCount  int
	store     cache.Store
	hasSynced func() (bool, error)
	stopCh    chan struct{}
}

// objectCache is a local cache of objects propagated via
// individual watches.
type objectCache struct {
	listObject    listObjectFunc
	watchObject   watchObjectFunc
	newObject     newObjectFunc
	groupResource schema.GroupResource

	lock  sync.Mutex
	items map[objectKey]*objectCacheItem
}

// NewObjectCache returns a new watch-based instance of Store interface.
func NewObjectCache(listObject listObjectFunc, watchObject watchObjectFunc, newObject newObjectFunc, groupResource schema.GroupResource) Store {
	return &objectCache{
		listObject:    listObject,
		watchObject:   watchObject,
		newObject:     newObject,
		groupResource: groupResource,
		items:         make(map[objectKey]*objectCacheItem),
	}
}

func (c *objectCache) newStore() cache.Store {
	// TODO: We may consider created a dedicated store keeping just a single
	// item, instead of using a generic store implementation for this purpose.
	// However, simple benchmarks show that memory overhead in that case is
	// decrease from ~600B to ~300B per object. So we are not optimizing it
	// until we will see a good reason for that.
	return cache.NewStore(cache.MetaNamespaceKeyFunc)
}

func (c *objectCache) newReflector(namespace, name string) *objectCacheItem {
	fieldSelector := fields.Set{"metadata.name": name}.AsSelector().String()
	listFunc := func(options metav1.ListOptions) (runtime.Object, error) {
		options.FieldSelector = fieldSelector
		return c.listObject(namespace, options)
	}
	watchFunc := func(options metav1.ListOptions) (watch.Interface, error) {
		options.FieldSelector = fieldSelector
		return c.watchObject(namespace, options)
	}
	store := c.newStore()
	reflector := cache.NewNamedReflector(
		fmt.Sprintf("object-%q/%q", namespace, name),
		&cache.ListWatch{ListFunc: listFunc, WatchFunc: watchFunc},
		c.newObject(),
		store,
		0,
	)
	stopCh := make(chan struct{})
	go reflector.Run(stopCh)
	return &objectCacheItem{
		refCount:  0,
		store:     store,
		hasSynced: func() (bool, error) { return reflector.LastSyncResourceVersion() != "", nil },
		stopCh:    stopCh,
	}
}

func (c *objectCache) AddReference(namespace, name string) {
	key := objectKey{namespace: namespace, name: name}

	// AddReference is called from RegisterPod thus it needs to be efficient.
	// Thus, it is only increaisng refCount and in case of first registration
	// of a given object it starts corresponding reflector.
	// It's responsibility of the first Get operation to wait until the
	// reflector propagated the store.
	c.lock.Lock()
	defer c.lock.Unlock()
	item, exists := c.items[key]
	if !exists {
		item = c.newReflector(namespace, name)
		c.items[key] = item
	}
	item.refCount++
}

func (c *objectCache) DeleteReference(namespace, name string) {
	key := objectKey{namespace: namespace, name: name}

	c.lock.Lock()
	defer c.lock.Unlock()
	if item, ok := c.items[key]; ok {
		item.refCount--
		if item.refCount == 0 {
			// Stop the underlying reflector.
			close(item.stopCh)
			delete(c.items, key)
		}
	}
}

// key returns key of an object with a given name and namespace.
// This has to be in-sync with cache.MetaNamespaceKeyFunc.
func (c *objectCache) key(namespace, name string) string {
	if len(namespace) > 0 {
		return namespace + "/" + name
	}
	return name
}

func (c *objectCache) Get(namespace, name string) (runtime.Object, error) {
	key := objectKey{namespace: namespace, name: name}

	c.lock.Lock()
	item, exists := c.items[key]
	c.lock.Unlock()

	if !exists {
		return nil, fmt.Errorf("object %q/%q not registered", namespace, name)
	}
	if err := wait.PollImmediate(10*time.Millisecond, time.Second, item.hasSynced); err != nil {
		return nil, fmt.Errorf("failed to sync %s cache: %v", c.groupResource.String(), err)
	}

	obj, exists, err := item.store.GetByKey(c.key(namespace, name))
	if err != nil {
		return nil, err
	}
	if !exists {
		return nil, apierrors.NewNotFound(c.groupResource, name)
	}
	if object, ok := obj.(runtime.Object); ok {
		return object, nil
	}
	return nil, fmt.Errorf("unexpected object type: %v", obj)
}

// NewWatchBasedManager creates a manager that keeps a cache of all objects
// necessary for registered pods.
// It implements the following logic:
// - whenever a pod is created or updated, we start individual watches for all
//   referenced objects that aren't referenced from other registered pods
// - every GetObject() returns a value from local cache propagated via watches
func NewWatchBasedManager(listObject listObjectFunc, watchObject watchObjectFunc, newObject newObjectFunc, groupResource schema.GroupResource, getReferencedObjects func(*v1.Pod) sets.String) Manager {
	objectStore := NewObjectCache(listObject, watchObject, newObject, groupResource)
	return NewCacheBasedManager(objectStore, getReferencedObjects)
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package seelog

import (
	"errors"
	"fmt"
	"sync"
)

func reportInternalError(err error) {
	fmt.Println("Seelog error: " + err.Error())
}

// LoggerInterface represents structs capable of logging Seelog messages
type LoggerInterface interface {

	// Tracef formats message according to format specifier
	// and writes to log with level = Trace.
	Tracef(format string, params ...interface{})

	// Debugf formats message according to format specifier
	// and writes to log with level = Debug.
	Debugf(format string, params ...interface{})

	// Infof formats message according to format specifier
	// and writes to log with level = Info.
	Infof(format string, params ...interface{})

	// Warnf formats message according to format specifier
	// and writes to log with level = Warn.
	Warnf(format string, params ...interface{}) error

	// Errorf formats message according to format specifier
	// and writes to log with level = Error.
	Errorf(format string, params ...interface{}) error

	// Criticalf formats message according to format specifier
	// and writes to log with level = Critical.
	Criticalf(format string, params ...interface{}) error

	// Trace formats message using the default formats for its operands
	// and writes to log with level = Trace
	Trace(v ...interface{})

	// Debug formats message using the default formats for its operands
	// and writes to log with level = Debug
	Debug(v ...interface{})

	// Info formats message using the default formats for its operands
	// and writes to log with level = Info
	Info(v ...interface{})

	// Warn formats message using the default formats for its operands
	// and writes to log with level = Warn
	Warn(v ...interface{}) error

	// Error formats message using the default formats for its operands
	// and writes to log with level = Error
	Error(v ...interface{}) error

	// Critical formats message using the default formats for its operands
	// and writes to log with level = Critical
	Critical(v ...interface{}) error

	traceWithCallDepth(callDepth int, message fmt.Stringer)
	debugWithCallDepth(callDepth int, message fmt.Stringer)
	infoWithCallDepth(callDepth int, message fmt.Stringer)
	warnWithCallDepth(callDepth int, message fmt.Stringer)
	errorWithCallDepth(callDepth int, message fmt.Stringer)
	criticalWithCallDepth(callDepth int, message fmt.Stringer)

	// Close flushes all the messages in the logger and closes it. It cannot be used after this operation.
	Close()

	// Flush flushes all the messages in the logger.
	Flush()

	// Closed returns true if the logger was previously closed.
	Closed() bool

	// SetAdditionalStackDepth sets the additional number of frames to skip by runtime.Caller
	// when getting function information needed to print seelog format identifiers such as %Func or %File.
	//
	// This func may be used when you wrap seelog funcs and want to print caller info of you own
	// wrappers instead of seelog func callers. In this case you should set depth = 1. If you then
	// wrap your wrapper, you should set depth = 2, etc.
	//
	// NOTE: Incorrect depth value may lead to errors in runtime.Caller evaluation or incorrect
	// function/file names in log files. Do not use it if you are not going to wrap seelog funcs.
	// You may reset the value to default using a SetAdditionalStackDepth(0) call.
	SetAdditionalStackDepth(depth int) error
}

// innerLoggerInterface is an internal logging interface
type innerLoggerInterface interface {
	innerLog(level LogLevel, context LogContextInterface, message fmt.Stringer)
	Flush()
}

// [file path][func name][level] -> [allowed]
type allowedContextCache map[string]map[string]map[LogLevel]bool

// commonLogger contains all common data needed for logging and contains methods used to log messages.
type commonLogger struct {
	config        *logConfig          // Config used for logging
	contextCache  allowedContextCache // Caches whether log is enabled for specific "full path-func name-level" sets
	closed        bool                // 'true' when all writers are closed, all data is flushed, logger is unusable.
	m             sync.Mutex          // Mutex for main operations
	unusedLevels  []bool
	innerLogger   innerLoggerInterface
	addStackDepth int // Additional stack depth needed for correct seelog caller context detection
}

func newCommonLogger(config *logConfig, internalLogger innerLoggerInterface) *commonLogger {
	cLogger := new(commonLogger)

	cLogger.config = config
	cLogger.contextCache = make(allowedContextCache)
	cLogger.unusedLevels = make([]bool, Off)
	cLogger.fillUnusedLevels()
	cLogger.innerLogger = internalLogger

	return cLogger
}

func (cLogger *commonLogger) SetAdditionalStackDepth(depth int) error {
	if depth < 0 {
		return fmt.Errorf("negative depth: %d", depth)
	}
	cLogger.m.Lock()
	cLogger.addStackDepth = depth
	cLogger.m.Unlock()
	return nil
}

func (cLogger *commonLogger) Tracef(format string, params ...interface{}) {
	cLogger.traceWithCallDepth(loggerFuncCallDepth, newLogFormattedMessage(format, params))
}

func (cLogger *commonLogger) Debugf(format string, params ...interface{}) {
	cLogger.debugWithCallDepth(loggerFuncCallDepth, newLogFormattedMessage(format, params))
}

func (cLogger *commonLogger) Infof(format string, params ...interface{}) {
	cLogger.infoWithCallDepth(loggerFuncCallDepth, newLogFormattedMessage(format, params))
}

func (cLogger *commonLogger) Warnf(format string, params ...interface{}) error {
	message := newLogFormattedMessage(format, params)
	cLogger.warnWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) Errorf(format string, params ...interface{}) error {
	message := newLogFormattedMessage(format, params)
	cLogger.errorWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) Criticalf(format string, params ...interface{}) error {
	message := newLogFormattedMessage(format, params)
	cLogger.criticalWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) Trace(v ...interface{}) {
	cLogger.traceWithCallDepth(loggerFuncCallDepth, newLogMessage(v))
}

func (cLogger *commonLogger) Debug(v ...interface{}) {
	cLogger.debugWithCallDepth(loggerFuncCallDepth, newLogMessage(v))
}

func (cLogger *commonLogger) Info(v ...interface{}) {
	cLogger.infoWithCallDepth(loggerFuncCallDepth, newLogMessage(v))
}

func (cLogger *commonLogger) Warn(v ...interface{}) error {
	message := newLogMessage(v)
	cLogger.warnWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) Error(v ...interface{}) error {
	message := newLogMessage(v)
	cLogger.errorWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) Critical(v ...interface{}) error {
	message := newLogMessage(v)
	cLogger.criticalWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) traceWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(TraceLvl, message, callDepth+cLogger.addStackDepth)
}

func (cLogger *commonLogger) debugWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(DebugLvl, message, callDepth+cLogger.addStackDepth)
}

func (cLogger *commonLogger) infoWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(InfoLvl, message, callDepth+cLogger.addStackDepth)
}

func (cLogger *commonLogger) warnWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(WarnLvl, message, callDepth+cLogger.addStackDepth)
}

func (cLogger *commonLogger) errorWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(ErrorLvl, message, callDepth+cLogger.addStackDepth)
}

func (cLogger *commonLogger) criticalWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(CriticalLvl, message, callDepth+cLogger.addStackDepth)
	cLogger.innerLogger.Flush()
}

func (cLogger *commonLogger) Closed() bool {
	return cLogger.closed
}

func (cLogger *commonLogger) fillUnusedLevels() {
	for i := 0; i < len(cLogger.unusedLevels); i++ {
		cLogger.unusedLevels[i] = true
	}

	cLogger.fillUnusedLevelsByContraint(cLogger.config.Constraints)

	for _, exception := range cLogger.config.Exceptions {
		cLogger.fillUnusedLevelsByContraint(exception)
	}
}

func (cLogger *commonLogger) fillUnusedLevelsByContraint(constraint logLevelConstraints) {
	for i := 0; i < len(cLogger.unusedLevels); i++ {
		if constraint.IsAllowed(LogLevel(i)) {
			cLogger.unusedLevels[i] = false
		}
	}
}

// stackCallDepth is used to indicate the call depth of 'log' func.
// This depth level is used in the runtime.Caller(...) call. See
// common_context.go -> specificContext, extractCallerInfo for details.
func (cLogger *commonLogger) log(
	level LogLevel,
	message fmt.Stringer,
	stackCallDepth int) {
	cLogger.m.Lock()
	defer cLogger.m.Unlock()

	if cLogger.Closed() {
		return
	}

	if cLogger.unusedLevels[level] {
		return
	}

	context, _ := specificContext(stackCallDepth)

	// Context errors are not reported because there are situations
	// in which context errors are normal Seelog usage cases. For
	// example in executables with stripped symbols.
	// Error contexts are returned instead. See common_context.go.
	/*if err != nil {
		reportInternalError(err)
		return
	}*/

	cLogger.innerLogger.innerLog(level, context, message)
}

func (cLogger *commonLogger) processLogMsg(
	level LogLevel,
	message fmt.Stringer,
	context LogContextInterface) {

	defer func() {
		if err := recover(); err != nil {
			reportInternalError(fmt.Errorf("Recovered from panic during message processing: %s", err))
		}
	}()

	if cLogger.config.IsAllowed(level, context) {
		cLogger.config.RootDispatcher.Dispatch(message.String(), level, context, reportInternalError)
	}
}

func (cLogger *commonLogger) isAllowed(level LogLevel, context LogContextInterface) bool {
	funcMap, ok := cLogger.contextCache[context.FullPath()]
	if !ok {
		funcMap = make(map[string]map[LogLevel]bool, 0)
		cLogger.contextCache[context.FullPath()] = funcMap
	}

	levelMap, ok := funcMap[context.Func()]
	if !ok {
		levelMap = make(map[LogLevel]bool, 0)
		funcMap[context.Func()] = levelMap
	}

	isAllowValue, ok := levelMap[level]
	if !ok {
		isAllowValue = cLogger.config.IsAllowed(level, context)
		levelMap[level] = isAllowValue
	}

	return isAllowValue
}

type logMessage struct {
	params []interface{}
}

type logFormattedMessage struct {
	format string
	params []interface{}
}

func newLogMessage(params []interface{}) fmt.Stringer {
	message := new(logMessage)

	message.params = params

	return message
}

func newLogFormattedMessage(format string, params []interface{}) *logFormattedMessage {
	message := new(logFormattedMessage)

	message.params = params
	message.format = format

	return message
}

func (message *logMessage) String() string {
	return fmt.Sprint(message.params...)
}

func (message *logFormattedMessage) String() string {
	return fmt.Sprintf(message.format, message.params...)
}
<commit_msg>Fix data race on read, not just write<commit_after>// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package seelog

import (
	"errors"
	"fmt"
	"sync"
)

func reportInternalError(err error) {
	fmt.Println("Seelog error: " + err.Error())
}

// LoggerInterface represents structs capable of logging Seelog messages
type LoggerInterface interface {

	// Tracef formats message according to format specifier
	// and writes to log with level = Trace.
	Tracef(format string, params ...interface{})

	// Debugf formats message according to format specifier
	// and writes to log with level = Debug.
	Debugf(format string, params ...interface{})

	// Infof formats message according to format specifier
	// and writes to log with level = Info.
	Infof(format string, params ...interface{})

	// Warnf formats message according to format specifier
	// and writes to log with level = Warn.
	Warnf(format string, params ...interface{}) error

	// Errorf formats message according to format specifier
	// and writes to log with level = Error.
	Errorf(format string, params ...interface{}) error

	// Criticalf formats message according to format specifier
	// and writes to log with level = Critical.
	Criticalf(format string, params ...interface{}) error

	// Trace formats message using the default formats for its operands
	// and writes to log with level = Trace
	Trace(v ...interface{})

	// Debug formats message using the default formats for its operands
	// and writes to log with level = Debug
	Debug(v ...interface{})

	// Info formats message using the default formats for its operands
	// and writes to log with level = Info
	Info(v ...interface{})

	// Warn formats message using the default formats for its operands
	// and writes to log with level = Warn
	Warn(v ...interface{}) error

	// Error formats message using the default formats for its operands
	// and writes to log with level = Error
	Error(v ...interface{}) error

	// Critical formats message using the default formats for its operands
	// and writes to log with level = Critical
	Critical(v ...interface{}) error

	traceWithCallDepth(callDepth int, message fmt.Stringer)
	debugWithCallDepth(callDepth int, message fmt.Stringer)
	infoWithCallDepth(callDepth int, message fmt.Stringer)
	warnWithCallDepth(callDepth int, message fmt.Stringer)
	errorWithCallDepth(callDepth int, message fmt.Stringer)
	criticalWithCallDepth(callDepth int, message fmt.Stringer)

	// Close flushes all the messages in the logger and closes it. It cannot be used after this operation.
	Close()

	// Flush flushes all the messages in the logger.
	Flush()

	// Closed returns true if the logger was previously closed.
	Closed() bool

	// SetAdditionalStackDepth sets the additional number of frames to skip by runtime.Caller
	// when getting function information needed to print seelog format identifiers such as %Func or %File.
	//
	// This func may be used when you wrap seelog funcs and want to print caller info of you own
	// wrappers instead of seelog func callers. In this case you should set depth = 1. If you then
	// wrap your wrapper, you should set depth = 2, etc.
	//
	// NOTE: Incorrect depth value may lead to errors in runtime.Caller evaluation or incorrect
	// function/file names in log files. Do not use it if you are not going to wrap seelog funcs.
	// You may reset the value to default using a SetAdditionalStackDepth(0) call.
	SetAdditionalStackDepth(depth int) error
}

// innerLoggerInterface is an internal logging interface
type innerLoggerInterface interface {
	innerLog(level LogLevel, context LogContextInterface, message fmt.Stringer)
	Flush()
}

// [file path][func name][level] -> [allowed]
type allowedContextCache map[string]map[string]map[LogLevel]bool

// commonLogger contains all common data needed for logging and contains methods used to log messages.
type commonLogger struct {
	config        *logConfig          // Config used for logging
	contextCache  allowedContextCache // Caches whether log is enabled for specific "full path-func name-level" sets
	closed        bool                // 'true' when all writers are closed, all data is flushed, logger is unusable.
	m             sync.Mutex          // Mutex for main operations
	unusedLevels  []bool
	innerLogger   innerLoggerInterface
	addStackDepth int // Additional stack depth needed for correct seelog caller context detection
}

func newCommonLogger(config *logConfig, internalLogger innerLoggerInterface) *commonLogger {
	cLogger := new(commonLogger)

	cLogger.config = config
	cLogger.contextCache = make(allowedContextCache)
	cLogger.unusedLevels = make([]bool, Off)
	cLogger.fillUnusedLevels()
	cLogger.innerLogger = internalLogger

	return cLogger
}

func (cLogger *commonLogger) SetAdditionalStackDepth(depth int) error {
	if depth < 0 {
		return fmt.Errorf("negative depth: %d", depth)
	}
	cLogger.m.Lock()
	cLogger.addStackDepth = depth
	cLogger.m.Unlock()
	return nil
}

func (cLogger *commonLogger) Tracef(format string, params ...interface{}) {
	cLogger.traceWithCallDepth(loggerFuncCallDepth, newLogFormattedMessage(format, params))
}

func (cLogger *commonLogger) Debugf(format string, params ...interface{}) {
	cLogger.debugWithCallDepth(loggerFuncCallDepth, newLogFormattedMessage(format, params))
}

func (cLogger *commonLogger) Infof(format string, params ...interface{}) {
	cLogger.infoWithCallDepth(loggerFuncCallDepth, newLogFormattedMessage(format, params))
}

func (cLogger *commonLogger) Warnf(format string, params ...interface{}) error {
	message := newLogFormattedMessage(format, params)
	cLogger.warnWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) Errorf(format string, params ...interface{}) error {
	message := newLogFormattedMessage(format, params)
	cLogger.errorWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) Criticalf(format string, params ...interface{}) error {
	message := newLogFormattedMessage(format, params)
	cLogger.criticalWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) Trace(v ...interface{}) {
	cLogger.traceWithCallDepth(loggerFuncCallDepth, newLogMessage(v))
}

func (cLogger *commonLogger) Debug(v ...interface{}) {
	cLogger.debugWithCallDepth(loggerFuncCallDepth, newLogMessage(v))
}

func (cLogger *commonLogger) Info(v ...interface{}) {
	cLogger.infoWithCallDepth(loggerFuncCallDepth, newLogMessage(v))
}

func (cLogger *commonLogger) Warn(v ...interface{}) error {
	message := newLogMessage(v)
	cLogger.warnWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) Error(v ...interface{}) error {
	message := newLogMessage(v)
	cLogger.errorWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) Critical(v ...interface{}) error {
	message := newLogMessage(v)
	cLogger.criticalWithCallDepth(loggerFuncCallDepth, message)
	return errors.New(message.String())
}

func (cLogger *commonLogger) traceWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(TraceLvl, message, callDepth, true)
}

func (cLogger *commonLogger) debugWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(DebugLvl, message, callDepth, true)
}

func (cLogger *commonLogger) infoWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(InfoLvl, message, callDepth, true)
}

func (cLogger *commonLogger) warnWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(WarnLvl, message, callDepth, true)
}

func (cLogger *commonLogger) errorWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(ErrorLvl, message, callDepth, true)
}

func (cLogger *commonLogger) criticalWithCallDepth(callDepth int, message fmt.Stringer) {
	cLogger.log(CriticalLvl, message, callDepth, true)
	cLogger.innerLogger.Flush()
}

func (cLogger *commonLogger) Closed() bool {
	return cLogger.closed
}

func (cLogger *commonLogger) fillUnusedLevels() {
	for i := 0; i < len(cLogger.unusedLevels); i++ {
		cLogger.unusedLevels[i] = true
	}

	cLogger.fillUnusedLevelsByContraint(cLogger.config.Constraints)

	for _, exception := range cLogger.config.Exceptions {
		cLogger.fillUnusedLevelsByContraint(exception)
	}
}

func (cLogger *commonLogger) fillUnusedLevelsByContraint(constraint logLevelConstraints) {
	for i := 0; i < len(cLogger.unusedLevels); i++ {
		if constraint.IsAllowed(LogLevel(i)) {
			cLogger.unusedLevels[i] = false
		}
	}
}

// stackCallDepth is used to indicate the call depth of 'log' func.
// This depth level is used in the runtime.Caller(...) call. See
// common_context.go -> specificContext, extractCallerInfo for details.
func (cLogger *commonLogger) log(
	level LogLevel,
	message fmt.Stringer,
	stackCallDepth int,
	useCallDepth bool) {
	cLogger.m.Lock()
	defer cLogger.m.Unlock()

	if cLogger.Closed() {
		return
	}

	if cLogger.unusedLevels[level] {
		return
	}

	if useCallDepth {
		stackCallDepth += cLogger.addStackDepth
	}

	context, _ := specificContext(stackCallDepth)

	// Context errors are not reported because there are situations
	// in which context errors are normal Seelog usage cases. For
	// example in executables with stripped symbols.
	// Error contexts are returned instead. See common_context.go.
	/*if err != nil {
		reportInternalError(err)
		return
	}*/

	cLogger.innerLogger.innerLog(level, context, message)
}

func (cLogger *commonLogger) processLogMsg(
	level LogLevel,
	message fmt.Stringer,
	context LogContextInterface) {

	defer func() {
		if err := recover(); err != nil {
			reportInternalError(fmt.Errorf("Recovered from panic during message processing: %s", err))
		}
	}()

	if cLogger.config.IsAllowed(level, context) {
		cLogger.config.RootDispatcher.Dispatch(message.String(), level, context, reportInternalError)
	}
}

func (cLogger *commonLogger) isAllowed(level LogLevel, context LogContextInterface) bool {
	funcMap, ok := cLogger.contextCache[context.FullPath()]
	if !ok {
		funcMap = make(map[string]map[LogLevel]bool, 0)
		cLogger.contextCache[context.FullPath()] = funcMap
	}

	levelMap, ok := funcMap[context.Func()]
	if !ok {
		levelMap = make(map[LogLevel]bool, 0)
		funcMap[context.Func()] = levelMap
	}

	isAllowValue, ok := levelMap[level]
	if !ok {
		isAllowValue = cLogger.config.IsAllowed(level, context)
		levelMap[level] = isAllowValue
	}

	return isAllowValue
}

type logMessage struct {
	params []interface{}
}

type logFormattedMessage struct {
	format string
	params []interface{}
}

func newLogMessage(params []interface{}) fmt.Stringer {
	message := new(logMessage)

	message.params = params

	return message
}

func newLogFormattedMessage(format string, params []interface{}) *logFormattedMessage {
	message := new(logFormattedMessage)

	message.params = params
	message.format = format

	return message
}

func (message *logMessage) String() string {
	return fmt.Sprint(message.params...)
}

func (message *logFormattedMessage) String() string {
	return fmt.Sprintf(message.format, message.params...)
}
<|endoftext|>


<commit_before>package sqlstore

import (
	"reflect"
	"testing"

	. "github.com/smartystreets/goconvey/convey"

	"github.com/grafana/grafana/pkg/components/simplejson"
	m "github.com/grafana/grafana/pkg/models"
)

func updateTestDashboard(dashboard *m.Dashboard, data map[string]interface{}) {
	data["title"] = dashboard.Title

	saveCmd := m.SaveDashboardCommand{
		OrgId:     dashboard.OrgId,
		Overwrite: true,
		Dashboard: simplejson.NewFromAny(data),
	}

	err := SaveDashboard(&saveCmd)
	So(err, ShouldBeNil)
}

func TestGetDashboardVersion(t *testing.T) {
	Convey("Testing dashboard version retrieval", t, func() {
		InitTestDB(t)

		Convey("Get a Dashboard ID and version ID", func() {
			savedDash := insertTestDashboard("test dash 26", 1, "diff")

			query := m.GetDashboardVersionQuery{
				DashboardId: savedDash.Id,
				Version:     savedDash.Version,
			}

			err := GetDashboardVersion(&query)
			So(err, ShouldBeNil)
			So(savedDash.Id, ShouldEqual, query.DashboardId)
			So(savedDash.Version, ShouldEqual, query.Version)

			dashCmd := m.GetDashboardQuery{
				OrgId: savedDash.OrgId,
				Slug:  savedDash.Slug,
			}
			err = GetDashboard(&dashCmd)
			So(err, ShouldBeNil)
			eq := reflect.DeepEqual(dashCmd.Result.Data, query.Result.Data)
			So(eq, ShouldEqual, true)
		})

		Convey("Attempt to get a version that doesn't exist", func() {
			query := m.GetDashboardVersionQuery{
				DashboardId: int64(999),
				Version:     123,
			}

			err := GetDashboardVersion(&query)
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, m.ErrDashboardVersionNotFound)
		})
	})
}

func TestGetDashboardVersions(t *testing.T) {
	Convey("Testing dashboard versions retrieval", t, func() {
		InitTestDB(t)
		savedDash := insertTestDashboard("test dash 43", 1, "diff-all")

		Convey("Get all versions for a given Dashboard ID", func() {
			query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}

			err := GetDashboardVersions(&query)
			So(err, ShouldBeNil)
			So(len(query.Result), ShouldEqual, 1)
		})

		Convey("Attempt to get the versions for a non-existent Dashboard ID", func() {
			query := m.GetDashboardVersionsQuery{DashboardId: int64(999), OrgId: 1}

			err := GetDashboardVersions(&query)
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, m.ErrNoVersionsForDashboardId)
			So(len(query.Result), ShouldEqual, 0)
		})

		Convey("Get all versions for an updated dashboard", func() {
			updateTestDashboard(savedDash, map[string]interface{}{
				"tags": "different-tag",
			})

			query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}
			err := GetDashboardVersions(&query)

			So(err, ShouldBeNil)
			So(len(query.Result), ShouldEqual, 2)
		})
	})
}

func TestCompareDashboardVersions(t *testing.T) {
	Convey("Testing dashboard version comparison", t, func() {
		InitTestDB(t)

		savedDash := insertTestDashboard("test dash 43", 1, "x")
		updateTestDashboard(savedDash, map[string]interface{}{
			"tags": "y",
		})

		Convey("Compare two versions that are different", func() {
			query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}

			err := GetDashboardVersions(&query)
			So(err, ShouldBeNil)
			So(len(query.Result), ShouldEqual, 2)

			cmd := m.CompareDashboardVersionsCommand{
				DashboardId: savedDash.Id,
				Original:    query.Result[0].Version,
				New:         query.Result[1].Version,
				DiffType:    m.DiffDelta,
			}

			err = CompareDashboardVersionsCommand(&cmd)
			So(err, ShouldBeNil)
			So(cmd.Delta, ShouldNotBeNil)
		})

		Convey("Compare two versions that are the same", func() {
			cmd := m.CompareDashboardVersionsCommand{
				DashboardId: savedDash.Id,
				Original:    savedDash.Version,
				New:         savedDash.Version,
				DiffType:    m.DiffDelta,
			}

			err := CompareDashboardVersionsCommand(&cmd)
			So(err, ShouldNotBeNil)
			So(cmd.Delta, ShouldBeNil)
		})

		Convey("Compare two versions that don't exist", func() {
			cmd := m.CompareDashboardVersionsCommand{
				DashboardId: savedDash.Id,
				Original:    123,
				New:         456,
				DiffType:    m.DiffDelta,
			}

			err := CompareDashboardVersionsCommand(&cmd)
			So(err, ShouldNotBeNil)
			So(cmd.Delta, ShouldBeNil)
		})
	})
}

func TestRestoreDashboardVersion(t *testing.T) {
	Convey("Testing dashboard version restoration", t, func() {
		InitTestDB(t)
		savedDash := insertTestDashboard("test dash 26", 1, "restore")
		updateTestDashboard(savedDash, map[string]interface{}{
			"tags": "not restore",
		})

		Convey("Restore dashboard to a previous version", func() {
			query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}
			err := GetDashboardVersions(&query)
			So(err, ShouldBeNil)

			cmd := m.RestoreDashboardVersionCommand{
				DashboardId: savedDash.Id,
				Version:     savedDash.Version,
				UserId:      0,
			}

			err = RestoreDashboardVersion(&cmd)
			So(err, ShouldBeNil)
		})
	})
}
<commit_msg>refactoring: fixed broken unit test in last commit<commit_after>package sqlstore

import (
	"reflect"
	"testing"

	. "github.com/smartystreets/goconvey/convey"

	"github.com/grafana/grafana/pkg/components/simplejson"
	m "github.com/grafana/grafana/pkg/models"
)

func updateTestDashboard(dashboard *m.Dashboard, data map[string]interface{}) {
	data["title"] = dashboard.Title

	saveCmd := m.SaveDashboardCommand{
		OrgId:     dashboard.OrgId,
		Overwrite: true,
		Dashboard: simplejson.NewFromAny(data),
	}

	err := SaveDashboard(&saveCmd)
	So(err, ShouldBeNil)
}

func TestGetDashboardVersion(t *testing.T) {
	Convey("Testing dashboard version retrieval", t, func() {
		InitTestDB(t)

		Convey("Get a Dashboard ID and version ID", func() {
			savedDash := insertTestDashboard("test dash 26", 1, "diff")

			query := m.GetDashboardVersionQuery{
				DashboardId: savedDash.Id,
				Version:     savedDash.Version,
			}

			err := GetDashboardVersion(&query)
			So(err, ShouldBeNil)
			So(savedDash.Id, ShouldEqual, query.DashboardId)
			So(savedDash.Version, ShouldEqual, query.Version)

			dashCmd := m.GetDashboardQuery{
				OrgId: savedDash.OrgId,
				Slug:  savedDash.Slug,
			}
			err = GetDashboard(&dashCmd)
			So(err, ShouldBeNil)
			eq := reflect.DeepEqual(dashCmd.Result.Data, query.Result.Data)
			So(eq, ShouldEqual, true)
		})

		Convey("Attempt to get a version that doesn't exist", func() {
			query := m.GetDashboardVersionQuery{
				DashboardId: int64(999),
				Version:     123,
			}

			err := GetDashboardVersion(&query)
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, m.ErrDashboardVersionNotFound)
		})
	})
}

func TestGetDashboardVersions(t *testing.T) {
	Convey("Testing dashboard versions retrieval", t, func() {
		InitTestDB(t)
		savedDash := insertTestDashboard("test dash 43", 1, "diff-all")

		Convey("Get all versions for a given Dashboard ID", func() {
			query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}

			err := GetDashboardVersions(&query)
			So(err, ShouldBeNil)
			So(len(query.Result), ShouldEqual, 1)
		})

		Convey("Attempt to get the versions for a non-existent Dashboard ID", func() {
			query := m.GetDashboardVersionsQuery{DashboardId: int64(999), OrgId: 1}

			err := GetDashboardVersions(&query)
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, m.ErrNoVersionsForDashboardId)
			So(len(query.Result), ShouldEqual, 0)
		})

		Convey("Get all versions for an updated dashboard", func() {
			updateTestDashboard(savedDash, map[string]interface{}{
				"tags": "different-tag",
			})

			query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}
			err := GetDashboardVersions(&query)

			So(err, ShouldBeNil)
			So(len(query.Result), ShouldEqual, 2)
		})
	})
}

func TestCompareDashboardVersions(t *testing.T) {
	Convey("Testing dashboard version comparison", t, func() {
		InitTestDB(t)

		savedDash := insertTestDashboard("test dash 43", 1, "x")
		updateTestDashboard(savedDash, map[string]interface{}{
			"tags": "y",
		})

		Convey("Compare two versions that are different", func() {
			query := m.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1}

			err := GetDashboardVersions(&query)
			So(err, ShouldBeNil)
			So(len(query.Result), ShouldEqual, 2)

			cmd := m.CompareDashboardVersionsCommand{
				DashboardId: savedDash.Id,
				Original:    query.Result[0].Version,
				New:         query.Result[1].Version,
				DiffType:    m.DiffDelta,
			}

			err = CompareDashboardVersionsCommand(&cmd)
			So(err, ShouldBeNil)
			So(cmd.Delta, ShouldNotBeNil)
		})

		Convey("Compare two versions that are the same", func() {
			cmd := m.CompareDashboardVersionsCommand{
				DashboardId: savedDash.Id,
				Original:    savedDash.Version,
				New:         savedDash.Version,
				DiffType:    m.DiffDelta,
			}

			err := CompareDashboardVersionsCommand(&cmd)
			So(err, ShouldNotBeNil)
			So(cmd.Delta, ShouldBeNil)
		})

		Convey("Compare two versions that don't exist", func() {
			cmd := m.CompareDashboardVersionsCommand{
				DashboardId: savedDash.Id,
				Original:    123,
				New:         456,
				DiffType:    m.DiffDelta,
			}

			err := CompareDashboardVersionsCommand(&cmd)
			So(err, ShouldNotBeNil)
			So(cmd.Delta, ShouldBeNil)
		})
	})
}
<|endoftext|>


<commit_before>package main

import log "github.com/cihub/seelog"

func initLog() {
	testConfig := `
<seelog>
	<outputs>
		<file type="size" path="./run.log" />
	</outputs>
</seelog>
`
	logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
	log.ReplaceLogger(logger)
}
<commit_msg>update logger<commit_after>package main

import log "github.com/cihub/seelog"

func initLog() {
	testConfig := `
<seelog>
	<outputs>
		<rollingfile type="size" filename="./run.log" maxsize="10000" maxrolls="5" />
	</outputs>
</seelog>
`
	logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
	log.ReplaceLogger(logger)
}
<|endoftext|>


<commit_before>// Copyright 2016 Afshin Darian. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

// Package logger provides a simple logging interface that supports multiple
// levels of logging. It goes up to 11.
package logger

import (
	"fmt"
	"log"

	"github.com/mgutz/ansi"
)

const (
	// No log output at all.
	Silent = iota
	// Only errors are logged.
	Error = iota
	// Blocking calls and lower are logged.
	Blocked = iota
	// Warnings and lower are logged.
	Warn = iota
	// Rejections (e.g., in a firewall) and lower are logged.
	Reject = iota
	// Listeners and lower are logged.
	Listen = iota
	// Install notifications and lower are logged.
	Install = iota
	// Initialization notifications and lower are logged.
	Init = iota
	// Incoming requests and lower are logged.
	Request = iota
	// Info output and lower are logged.
	Info = iota
	// All log output is shown.
	Debug = iota
	max   = iota
)

// Logger only outputs log messages that are equal or lower than its log level.
type Logger struct{ level int }

// LogLevel translates human-readable log level names to their int values.
var LogLevel = map[string]int{
	"silent":  Silent,
	"error":   Error,
	"blocked": Blocked,
	"warn":    Warn,
	"reject":  Reject,
	"listen":  Listen,
	"install": Install,
	"init":    Init,
	"request": Request,
	"info":    Info,
	"debug":   Debug}

var prefixes = [...]string{
	"",
	ansi.Color("[***error***]", "black:red"),
	ansi.Color("[**blocked**]", "255+b:165"),
	ansi.Color("[**warning**]", "red:yellow+h"),
	ansi.Color("[ rejection ]", "125+b:208"),
	ansi.Color("[ listening ]", "black:cyan+h"),
	/*      */ "[ installed ]",
	/*      */ "[initialized]",
	/*      */ "[  request  ]",
	/*      */ "[information]",
	/*      */ "[   debug   ]"}

func out(loggerLevel, messageLevel int, format string, v ...interface{}) {
	if loggerLevel == Silent || messageLevel == Silent {
		return
	}
	message := fmt.Sprintf(format, v...)
	if messageLevel > Silent && messageLevel <= loggerLevel {
		log.Printf("%s %s", prefixes[messageLevel], message)
	}
}

// Level returns a logger instance's log level if logger level allows.
func (logger *Logger) Level() int { return logger.level }

// SetLevel sets a logger instance's log level if logger level allows.
func (logger *Logger) SetLevel(level int) error {
	if level > Debug || level < Silent {
		return fmt.Errorf("logger level must be >= %d and < %d", Silent, max)
	}
	logger.level = level
	return nil
}

// Error logs an error if logger level allows.
func (logger *Logger) Error(format string, v ...interface{}) {
	out(logger.level, Error, format, v...)
}

// Blocked logs a blocked message if logger level allows.
func (logger *Logger) Blocked(format string, v ...interface{}) {
	out(logger.level, Blocked, format, v...)
}

// Warn logs a warning if logger level allows.
func (logger *Logger) Warn(format string, v ...interface{}) {
	out(logger.level, Warn, format, v...)
}

// Reject logs a rejection if logger level allows.
func (logger *Logger) Reject(format string, v ...interface{}) {
	out(logger.level, Reject, format, v...)
}

// Listen logs a listener message if logger level allows.
func (logger *Logger) Listen(format string, v ...interface{}) {
	out(logger.level, Listen, format, v...)
}

// Install logs an install message if logger level allows.
func (logger *Logger) Install(format string, v ...interface{}) {
	out(logger.level, Install, format, v...)
}

// Init logs an initialization message if logger level allows.
func (logger *Logger) Init(format string, v ...interface{}) {
	out(logger.level, Init, format, v...)
}

// Request logs a request if logger level allows.
func (logger *Logger) Request(format string, v ...interface{}) {
	out(logger.level, Request, format, v...)
}

// Info logs an info message if logger level allows.
func (logger *Logger) Info(format string, v ...interface{}) {
	out(logger.level, Info, format, v...)
}

// Debug logs a debug message if logger level allows.
func (logger *Logger) Debug(format string, v ...interface{}) {
	out(logger.level, Debug, format, v...)
}

// MustError logs an error.
func MustError(format string, v ...interface{}) {
	out(max, Error, format, v...)
}

// MustBlocked logs a blocked message.
func MustBlocked(format string, v ...interface{}) {
	out(max, Blocked, format, v...)
}

// MustWarn logs a warning.
func MustWarn(format string, v ...interface{}) {
	out(max, Warn, format, v...)
}

// MustReject logs a rejection.
func MustReject(format string, v ...interface{}) {
	out(max, Reject, format, v...)
}

// MustListen logs a listener message.
func MustListen(format string, v ...interface{}) {
	out(max, Listen, format, v...)
}

// MustInstall logs an install message.
func MustInstall(format string, v ...interface{}) {
	out(max, Install, format, v...)
}

// MustInit logs an initialization message.
func MustInit(format string, v ...interface{}) {
	out(max, Init, format, v...)
}

// MustRequest logs a request.
func MustRequest(format string, v ...interface{}) {
	out(max, Request, format, v...)
}

// MustInfo logs an info message.
func MustInfo(format string, v ...interface{}) {
	out(max, Info, format, v...)
}

// MustDebug logs a debug message.
func MustDebug(format string, v ...interface{}) {
	out(max, Debug, format, v...)
}

// New instantiates a Logger and sets its level. If the level is invalid, it
// returns an error.
func New(level int) (*Logger, error) {
	logger := new(Logger)
	if err := logger.SetLevel(level); err != nil {
		return nil, err
	} else {
		return logger, nil
	}
}
<commit_msg>logger => l<commit_after>// Copyright 2016 Afshin Darian. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

// Package logger provides a simple logging interface that supports multiple
// levels of logging. It goes up to 11.
package logger

import (
	"fmt"
	"log"

	"github.com/mgutz/ansi"
)

const (
	// No log output at all.
	Silent = iota
	// Only errors are logged.
	Error = iota
	// Blocking calls and lower are logged.
	Blocked = iota
	// Warnings and lower are logged.
	Warn = iota
	// Rejections (e.g., in a firewall) and lower are logged.
	Reject = iota
	// Listeners and lower are logged.
	Listen = iota
	// Install notifications and lower are logged.
	Install = iota
	// Initialization notifications and lower are logged.
	Init = iota
	// Incoming requests and lower are logged.
	Request = iota
	// Info output and lower are logged.
	Info = iota
	// All log output is shown.
	Debug = iota
	max   = iota
)

// Logger only outputs log messages that are equal or lower than its log level.
type Logger struct{ level int }

// LogLevel translates human-readable log level names to their int values.
var LogLevel = map[string]int{
	"silent":  Silent,
	"error":   Error,
	"blocked": Blocked,
	"warn":    Warn,
	"reject":  Reject,
	"listen":  Listen,
	"install": Install,
	"init":    Init,
	"request": Request,
	"info":    Info,
	"debug":   Debug}

var prefixes = [...]string{
	"",
	ansi.Color("[***error***]", "black:red"),
	ansi.Color("[**blocked**]", "255+b:165"),
	ansi.Color("[**warning**]", "red:yellow+h"),
	ansi.Color("[ rejection ]", "125+b:208"),
	ansi.Color("[ listening ]", "black:cyan+h"),
	/*      */ "[ installed ]",
	/*      */ "[initialized]",
	/*      */ "[  request  ]",
	/*      */ "[information]",
	/*      */ "[   debug   ]"}

func out(loggerLevel, messageLevel int, format string, v ...interface{}) {
	if loggerLevel == Silent || messageLevel == Silent {
		return
	}
	message := fmt.Sprintf(format, v...)
	if messageLevel > Silent && messageLevel <= loggerLevel {
		log.Printf("%s %s", prefixes[messageLevel], message)
	}
}

// Level returns a logger instance's log level if logger level allows.
func (l *Logger) Level() int { return l.level }

// SetLevel sets a logger instance's log level if logger level allows.
func (l *Logger) SetLevel(level int) error {
	if level > Debug || level < Silent {
		return fmt.Errorf("logger level must be >= %d and < %d", Silent, max)
	}
	l.level = level
	return nil
}

// Error logs an error if logger level allows.
func (l *Logger) Error(format string, v ...interface{}) {
	out(l.level, Error, format, v...)
}

// Blocked logs a blocked message if logger level allows.
func (l *Logger) Blocked(format string, v ...interface{}) {
	out(l.level, Blocked, format, v...)
}

// Warn logs a warning if logger level allows.
func (l *Logger) Warn(format string, v ...interface{}) {
	out(l.level, Warn, format, v...)
}

// Reject logs a rejection if logger level allows.
func (l *Logger) Reject(format string, v ...interface{}) {
	out(l.level, Reject, format, v...)
}

// Listen logs a listener message if logger level allows.
func (l *Logger) Listen(format string, v ...interface{}) {
	out(l.level, Listen, format, v...)
}

// Install logs an install message if logger level allows.
func (l *Logger) Install(format string, v ...interface{}) {
	out(l.level, Install, format, v...)
}

// Init logs an initialization message if logger level allows.
func (l *Logger) Init(format string, v ...interface{}) {
	out(l.level, Init, format, v...)
}

// Request logs a request if logger level allows.
func (l *Logger) Request(format string, v ...interface{}) {
	out(l.level, Request, format, v...)
}

// Info logs an info message if logger level allows.
func (l *Logger) Info(format string, v ...interface{}) {
	out(l.level, Info, format, v...)
}

// Debug logs a debug message if logger level allows.
func (l *Logger) Debug(format string, v ...interface{}) {
	out(l.level, Debug, format, v...)
}

// MustError logs an error.
func MustError(format string, v ...interface{}) {
	out(max, Error, format, v...)
}

// MustBlocked logs a blocked message.
func MustBlocked(format string, v ...interface{}) {
	out(max, Blocked, format, v...)
}

// MustWarn logs a warning.
func MustWarn(format string, v ...interface{}) {
	out(max, Warn, format, v...)
}

// MustReject logs a rejection.
func MustReject(format string, v ...interface{}) {
	out(max, Reject, format, v...)
}

// MustListen logs a listener message.
func MustListen(format string, v ...interface{}) {
	out(max, Listen, format, v...)
}

// MustInstall logs an install message.
func MustInstall(format string, v ...interface{}) {
	out(max, Install, format, v...)
}

// MustInit logs an initialization message.
func MustInit(format string, v ...interface{}) {
	out(max, Init, format, v...)
}

// MustRequest logs a request.
func MustRequest(format string, v ...interface{}) {
	out(max, Request, format, v...)
}

// MustInfo logs an info message.
func MustInfo(format string, v ...interface{}) {
	out(max, Info, format, v...)
}

// MustDebug logs a debug message.
func MustDebug(format string, v ...interface{}) {
	out(max, Debug, format, v...)
}

// New instantiates a Logger and sets its level. If the level is invalid, it
// returns an error.
func New(level int) (*Logger, error) {
	l := new(Logger)
	if err := l.SetLevel(level); err != nil {
		return nil, err
	} else {
		return l, nil
	}
}
<|endoftext|>


<commit_before>package logging

import (
	"log"
)

/*
Logger represents an instance of a log structure
*/
type Logger struct {
	ApplicationName string
	LogLevel        LogType

	logLevelInt int
}

/*
Debug writes a debug entry to the log
*/
func (logger *Logger) Debug(message ...interface{}) {
	logger.writeLog(DEBUG, message)
}

/*
Error writes an error message to the log
*/
func (logger *Logger) Error(message ...interface{}) {
	logger.writeLog(ERROR, message)
}

/*
Fatal writes a fatal log messge
*/
func (logger *Logger) Fatal(message ...interface{}) {
	logger.writeLog(FATAL, message)
}

/*
Info writes an information message to the log
*/
func (logger *Logger) Info(message ...interface{}) {
	logger.writeLog(INFO, message)
}

/*
NewLogger creates a new Logger instance with a specific application name.
The application name is a prefix used in all log messges.
*/
func NewLogger(applicationName string) *Logger {
	return &Logger{
		ApplicationName: applicationName,
		LogLevel:        DEBUG,

		logLevelInt: int(DEBUG),
	}
}

/*
NewLoggerWithMinimumLevel creates a new Logger instance that only logs
messages with a specified log type level or higher.
*/
func newLoggerWithMinimumLevel(applicationName string, logLevel LogType) *Logger {
	return &Logger{
		ApplicationName: applicationName,
		LogLevel:        logLevel,

		logLevelInt: int(logLevel),
	}
}

/*
Warning writes a warning message to the log
*/
func (logger *Logger) Warning(message ...interface{}) {
	logger.writeLog(WARN, message)
}

func (logger *Logger) writeLog(logType LogType, message ...interface{}) {
	logLevelInt := int(logType)

	if logLevelInt >= logger.logLevelInt {
		log.SetPrefix(logger.ApplicationName + ": " + logType.String() + " - ")

		for _, item := range message {
			log.Print(item)
		}
	}
}
<commit_msg>Missed a commit<commit_after>package logging

import (
	"log"
)

/*
Logger represents an instance of a log structure
*/
type Logger struct {
	ApplicationName string
	LogLevel        LogType

	logLevelInt int
}

/*
Debug writes a debug entry to the log
*/
func (logger *Logger) Debug(message ...interface{}) {
	logger.writeLog(DEBUG, message)
}

/*
Error writes an error message to the log
*/
func (logger *Logger) Error(message ...interface{}) {
	logger.writeLog(ERROR, message)
}

/*
Fatal writes a fatal log messge
*/
func (logger *Logger) Fatal(message ...interface{}) {
	logger.writeLog(FATAL, message)
}

/*
Info writes an information message to the log
*/
func (logger *Logger) Info(message ...interface{}) {
	logger.writeLog(INFO, message)
}

/*
NewLogger creates a new Logger instance with a specific application name.
The application name is a prefix used in all log messges.
*/
func NewLogger(applicationName string) *Logger {
	return &Logger{
		ApplicationName: applicationName,
		LogLevel:        DEBUG,

		logLevelInt: int(DEBUG),
	}
}

/*
NewLoggerWithMinimumLevel creates a new Logger instance that only logs
messages with a specified log type level or higher.
*/
func NewLoggerWithMinimumLevel(applicationName string, logLevel LogType) *Logger {
	return &Logger{
		ApplicationName: applicationName,
		LogLevel:        logLevel,

		logLevelInt: int(logLevel),
	}
}

/*
Warning writes a warning message to the log
*/
func (logger *Logger) Warning(message ...interface{}) {
	logger.writeLog(WARN, message)
}

func (logger *Logger) writeLog(logType LogType, message ...interface{}) {
	logLevelInt := int(logType)

	if logLevelInt >= logger.logLevelInt {
		log.SetPrefix(logger.ApplicationName + ": " + logType.String() + " - ")

		for _, item := range message {
			log.Print(item)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"fmt"
	"io"
	"os"
	"time"

	"github.com/mattn/go-isatty"
)

var (
	green        = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
	white        = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
	yellow       = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
	red          = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
	blue         = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
	magenta      = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
	cyan         = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
	reset        = string([]byte{27, 91, 48, 109})
	disableColor = false
)

func DisableConsoleColor() {
	disableColor = true
}

func ErrorLogger() HandlerFunc {
	return ErrorLoggerT(ErrorTypeAny)
}

func ErrorLoggerT(typ ErrorType) HandlerFunc {
	return func(c *Context) {
		c.Next()
		errors := c.Errors.ByType(typ)
		if len(errors) > 0 {
			c.JSON(-1, errors)
		}
	}
}

// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
func Logger() HandlerFunc {
	return LoggerWithWriter(DefaultWriter)
}

// LoggerWithWriter instance a Logger middleware with the specified writter buffer.
// Example: os.Stdout, a file opened in write mode, a socket...
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
	isTerm := true

	if w, ok := out.(*os.File); !ok || !isatty.IsTerminal(w.Fd()) || disableColor {
		isTerm = false
	}

	var skip map[string]struct{}

	if length := len(notlogged); length > 0 {
		skip = make(map[string]struct{}, length)

		for _, path := range notlogged {
			skip[path] = struct{}{}
		}
	}

	return func(c *Context) {
		// Start timer
		start := time.Now()
		path := c.Request.URL.Path

		// Process request
		c.Next()

		// Log only when path is not being skipped
		if _, ok := skip[path]; !ok {
			// Stop timer
			end := time.Now()
			latency := end.Sub(start)

			clientIP := c.ClientIP()
			method := c.Request.Method
			statusCode := c.Writer.Status()
			var statusColor, methodColor string
			if isTerm {
				statusColor = colorForStatus(statusCode)
				methodColor = colorForMethod(method)
			}
			comment := c.Errors.ByType(ErrorTypePrivate).String()

			fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %s |%s  %s %-7s %s\n%s",
				end.Format("2006/01/02 - 15:04:05"),
				statusColor, statusCode, reset,
				latency,
				clientIP,
				methodColor, method, reset,
				path,
				comment,
			)
		}
	}
}

func colorForStatus(code int) string {
	switch {
	case code >= 200 && code < 300:
		return green
	case code >= 300 && code < 400:
		return white
	case code >= 400 && code < 500:
		return yellow
	default:
		return red
	}
}

func colorForMethod(method string) string {
	switch method {
	case "GET":
		return blue
	case "POST":
		return cyan
	case "PUT":
		return yellow
	case "DELETE":
		return red
	case "PATCH":
		return green
	case "HEAD":
		return magenta
	case "OPTIONS":
		return white
	default:
		return reset
	}
}
<commit_msg>better display for log message (#623)<commit_after>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"fmt"
	"io"
	"os"
	"time"

	"github.com/mattn/go-isatty"
)

var (
	green        = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
	white        = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
	yellow       = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
	red          = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
	blue         = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
	magenta      = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
	cyan         = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
	reset        = string([]byte{27, 91, 48, 109})
	disableColor = false
)

func DisableConsoleColor() {
	disableColor = true
}

func ErrorLogger() HandlerFunc {
	return ErrorLoggerT(ErrorTypeAny)
}

func ErrorLoggerT(typ ErrorType) HandlerFunc {
	return func(c *Context) {
		c.Next()
		errors := c.Errors.ByType(typ)
		if len(errors) > 0 {
			c.JSON(-1, errors)
		}
	}
}

// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
func Logger() HandlerFunc {
	return LoggerWithWriter(DefaultWriter)
}

// LoggerWithWriter instance a Logger middleware with the specified writter buffer.
// Example: os.Stdout, a file opened in write mode, a socket...
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
	isTerm := true

	if w, ok := out.(*os.File); !ok || !isatty.IsTerminal(w.Fd()) || disableColor {
		isTerm = false
	}

	var skip map[string]struct{}

	if length := len(notlogged); length > 0 {
		skip = make(map[string]struct{}, length)

		for _, path := range notlogged {
			skip[path] = struct{}{}
		}
	}

	return func(c *Context) {
		// Start timer
		start := time.Now()
		path := c.Request.URL.Path

		// Process request
		c.Next()

		// Log only when path is not being skipped
		if _, ok := skip[path]; !ok {
			// Stop timer
			end := time.Now()
			latency := end.Sub(start)

			clientIP := c.ClientIP()
			method := c.Request.Method
			statusCode := c.Writer.Status()
			var statusColor, methodColor string
			if isTerm {
				statusColor = colorForStatus(statusCode)
				methodColor = colorForMethod(method)
			}
			comment := c.Errors.ByType(ErrorTypePrivate).String()

			fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %15s |%s  %s %-7s %s\n%s",
				end.Format("2006/01/02 - 15:04:05"),
				statusColor, statusCode, reset,
				latency,
				clientIP,
				methodColor, method, reset,
				path,
				comment,
			)
		}
	}
}

func colorForStatus(code int) string {
	switch {
	case code >= 200 && code < 300:
		return green
	case code >= 300 && code < 400:
		return white
	case code >= 400 && code < 500:
		return yellow
	default:
		return red
	}
}

func colorForMethod(method string) string {
	switch method {
	case "GET":
		return blue
	case "POST":
		return cyan
	case "PUT":
		return yellow
	case "DELETE":
		return red
	case "PATCH":
		return green
	case "HEAD":
		return magenta
	case "OPTIONS":
		return white
	default:
		return reset
	}
}
<|endoftext|>