vendor github.com/docker/docker to bcaa613d823

Signed-off-by: Tibor Vass <tibor@docker.com>
This commit is contained in:
Tibor Vass 2019-04-03 19:06:12 +00:00
parent 39f30ef168
commit 45ec86b10f
137 changed files with 1937 additions and 665 deletions

View File

@ -10,6 +10,7 @@ import (
"fmt"
"io"
"io/ioutil"
"net"
"os"
"path/filepath"
"regexp"
@ -413,7 +414,10 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
if s != nil {
go func() {
logrus.Debugf("running session: %v", s.ID())
if err := s.Run(ctx, dockerCli.Client().DialSession); err != nil {
dialSession := func(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) {
return dockerCli.Client().DialHijack(ctx, "/session", proto, meta)
}
if err := s.Run(ctx, dialSession); err != nil {
logrus.Error(err)
cancel() // cancel progress context
}

View File

@ -8,6 +8,7 @@ import (
"fmt"
"io"
"io/ioutil"
"net"
"os"
"path/filepath"
"strings"
@ -190,8 +191,11 @@ func runBuildBuildKit(dockerCli command.Cli, options buildOptions) error {
eg, ctx := errgroup.WithContext(ctx)
dialSession := func(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) {
return dockerCli.Client().DialHijack(ctx, "/session", proto, meta)
}
eg.Go(func() error {
return s.Run(context.TODO(), dockerCli.Client().DialSession)
return s.Run(context.TODO(), dialSession)
})
buildID := stringid.GenerateRandomID()

View File

@ -13,7 +13,7 @@ github.com/cpuguy83/go-md2man v1.0.8
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76 # v1.1.0
github.com/dgrijalva/jwt-go a2c85815a77d0f951e33ba4db5ae93629a1530af
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
github.com/docker/docker 827cb09f87964ed38b46502f22a585f2ed4a78e1
github.com/docker/docker bcaa613d823afa461957e7ad17faade03d82656f
github.com/docker/compose-on-kubernetes v0.4.21
github.com/docker/docker-credential-helpers 5241b46610f2491efdf9d1c85f1ddf5b02f6d962
# the docker/go package contains a customized version of canonical/json
@ -25,7 +25,7 @@ github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
github.com/docker/go-units 47565b4f722fb6ceae66b95f853feed578a4a51c # v0.3.3
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
github.com/docker/licensing 9781369abdb5281cdc07a2a446c6df01347ec793
github.com/docker/swarmkit 415dc72789e2b733ea884f09188c286ca187d8ec
github.com/docker/swarmkit 18e7e58ea1a5ec016625a636d0d52500eea123bc
github.com/evanphx/json-patch v4.1.0
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
@ -47,8 +47,8 @@ github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 #
github.com/json-iterator/go 0ff49de124c6f76f8494e194af75bde0f1a49a29 # 1.1.6
github.com/mattn/go-shellwords a72fbe27a1b0ed0df2f02754945044ce1456608b # v1.0.5
github.com/matttproud/golang_protobuf_extensions v1.0.1
github.com/Microsoft/hcsshim v0.8.6
github.com/Microsoft/go-winio v0.4.12
github.com/Microsoft/hcsshim ba3d6667710fa905116f39a19d059c4c1016be7c
github.com/Microsoft/go-winio c599b533b43b1363d7d7c6cfda5ede70ed73ff13
github.com/miekg/pkcs11 6120d95c0e9576ccf4a78ba40855809dca31a9ed
github.com/mitchellh/mapstructure f15292f7a699fcc1a38a80977f80a046874ba8ac
github.com/moby/buildkit 62e5542790fe1d1cf9ca6302d5a8b988df99159a
@ -67,7 +67,7 @@ github.com/prometheus/common 7600349dcfe1abd18d72d3a1770870d9800a7801
github.com/prometheus/procfs 7d6f385de8bea29190f15ba9931442a0eaef9af7
github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77
github.com/sirupsen/logrus v1.0.6
github.com/sirupsen/logrus v1.3.0
github.com/spf13/cobra v0.0.3
# temporary fork with https://github.com/spf13/pflag/pull/170 applied, which isn't merged yet upstream
github.com/spf13/pflag 4cb166e4f25ac4e8016a3595bbf7ea2e9aa85a2c https://github.com/thaJeztah/pflag.git
@ -80,7 +80,7 @@ github.com/tonistiigi/units 6950e57a87eaf136bbe44ef2ec8e75b9e3569de2
github.com/xeipuuv/gojsonpointer 4e3ac2762d5f479393488629ee9370b50873b3a6
github.com/xeipuuv/gojsonreference bd5ef7bd5415a7ac448318e64f11a24cd21e594b
github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d
golang.org/x/crypto 0709b304e793a5edb4a2c0145f281ecdc20838a4
golang.org/x/crypto b7391e95e576cacdcdd422573063bc057239113d
golang.org/x/net a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1
golang.org/x/oauth2 ef147856a6ddbb60760db74283d2424e98c87bff
golang.org/x/sync 42b317875d0fa942474b76e1b46a6060d720ae6e
@ -101,3 +101,4 @@ k8s.io/kubernetes v1.14.0
k8s.io/utils 21c4ce38f2a793ec01e925ddc31216500183b773
vbom.ml/util 256737ac55c46798123f754ab7d2c784e2c71783
sigs.k8s.io/yaml v1.1.0
github.com/konsorten/go-windows-terminal-sequences v1.0.1

View File

@ -23,6 +23,10 @@ type Process struct {
callbackNumber uintptr
logctx logrus.Fields
closedWaitOnce sync.Once
waitBlock chan struct{}
waitError error
}
func newProcess(process hcsProcess, processID int, computeSystem *System) *Process {
@ -34,6 +38,7 @@ func newProcess(process hcsProcess, processID int, computeSystem *System) *Proce
logfields.ContainerID: computeSystem.ID(),
logfields.ProcessID: processID,
},
waitBlock: make(chan struct{}),
}
}
@ -163,33 +168,49 @@ func (process *Process) Kill() (err error) {
return nil
}
// Wait waits for the process to exit.
// waitBackground waits for the process exit notification. Once received sets
// `process.waitError` (if any) and unblocks all `Wait` and `WaitTimeout` calls.
//
// This MUST be called exactly once per `process.handle` but `Wait` and
// `WaitTimeout` are safe to call multiple times.
func (process *Process) waitBackground() {
process.waitError = waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil)
process.closedWaitOnce.Do(func() {
close(process.waitBlock)
})
}
// Wait waits for the process to exit. If the process has already exited returns
// the pervious error (if any).
func (process *Process) Wait() (err error) {
operation := "hcsshim::Process::Wait"
process.logOperationBegin(operation)
defer func() { process.logOperationEnd(operation, err) }()
err = waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil)
if err != nil {
<-process.waitBlock
if process.waitError != nil {
return makeProcessError(process, operation, err, nil)
}
return nil
}
// WaitTimeout waits for the process to exit or the duration to elapse. It returns
// false if timeout occurs.
// WaitTimeout waits for the process to exit or the duration to elapse. If the
// process has already exited returns the pervious error (if any). If a timeout
// occurs returns `ErrTimeout`.
func (process *Process) WaitTimeout(timeout time.Duration) (err error) {
operation := "hcssshim::Process::WaitTimeout"
process.logOperationBegin(operation)
defer func() { process.logOperationEnd(operation, err) }()
err = waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout)
if err != nil {
return makeProcessError(process, operation, err, nil)
select {
case <-process.waitBlock:
if process.waitError != nil {
return makeProcessError(process, operation, process.waitError, nil)
}
return nil
case <-time.After(timeout):
return makeProcessError(process, operation, ErrTimeout, nil)
}
}
// ResizeConsole resizes the console of the process.
@ -276,15 +297,20 @@ func (process *Process) ExitCode() (_ int, err error) {
properties, err := process.Properties()
if err != nil {
return 0, makeProcessError(process, operation, err, nil)
return -1, makeProcessError(process, operation, err, nil)
}
if properties.Exited == false {
return 0, makeProcessError(process, operation, ErrInvalidProcessState, nil)
return -1, makeProcessError(process, operation, ErrInvalidProcessState, nil)
}
if properties.LastWaitResult != 0 {
return 0, makeProcessError(process, operation, syscall.Errno(properties.LastWaitResult), nil)
logrus.WithFields(logrus.Fields{
logfields.ContainerID: process.SystemID(),
logfields.ProcessID: process.processID,
"wait-result": properties.LastWaitResult,
}).Warn("hcsshim::Process::ExitCode - Non-zero last wait result")
return -1, nil
}
return int(properties.ExitCode), nil
@ -397,6 +423,9 @@ func (process *Process) Close() (err error) {
}
process.handle = 0
process.closedWaitOnce.Do(func() {
close(process.waitBlock)
})
return nil
}
@ -450,7 +479,7 @@ func (process *Process) unregisterCallback() error {
closeChannels(context.channels)
callbackMapLock.Lock()
callbackMap[callbackNumber] = nil
delete(callbackMap, callbackNumber)
callbackMapLock.Unlock()
handle = 0

View File

@ -43,6 +43,10 @@ type System struct {
callbackNumber uintptr
logctx logrus.Fields
closedWaitOnce sync.Once
waitBlock chan struct{}
waitError error
}
func newSystem(id string) *System {
@ -51,6 +55,7 @@ func newSystem(id string) *System {
logctx: logrus.Fields{
logfields.ContainerID: id,
},
waitBlock: make(chan struct{}),
}
}
@ -121,6 +126,8 @@ func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (_ *System
return nil, makeSystemError(computeSystem, operation, hcsDocument, err, events)
}
go computeSystem.waitBackground()
return computeSystem, nil
}
@ -153,6 +160,7 @@ func OpenComputeSystem(id string) (_ *System, err error) {
if err = computeSystem.registerCallback(); err != nil {
return nil, makeSystemError(computeSystem, operation, "", err, nil)
}
go computeSystem.waitBackground()
return computeSystem, nil
}
@ -280,7 +288,7 @@ func (computeSystem *System) Shutdown() (err error) {
operation := "hcsshim::ComputeSystem::Shutdown"
computeSystem.logOperationBegin(operation)
defer func() {
if IsAlreadyStopped(err) {
if IsAlreadyClosed(err) || IsAlreadyStopped(err) || IsPending(err) {
computeSystem.logOperationEnd(operation, nil)
} else {
computeSystem.logOperationEnd(operation, err)
@ -312,7 +320,7 @@ func (computeSystem *System) Terminate() (err error) {
operation := "hcsshim::ComputeSystem::Terminate"
computeSystem.logOperationBegin(operation)
defer func() {
if IsPending(err) {
if IsAlreadyClosed(err) || IsAlreadyStopped(err) || IsPending(err) {
computeSystem.logOperationEnd(operation, nil)
} else {
computeSystem.logOperationEnd(operation, err)
@ -335,48 +343,67 @@ func (computeSystem *System) Terminate() (err error) {
return nil
}
// Wait synchronously waits for the compute system to shutdown or terminate.
// waitBackground waits for the compute system exit notification. Once received
// sets `computeSystem.waitError` (if any) and unblocks all `Wait`,
// `WaitExpectedError`, and `WaitTimeout` calls.
//
// This MUST be called exactly once per `computeSystem.handle` but `Wait`,
// `WaitExpectedError`, and `WaitTimeout` are safe to call multiple times.
func (computeSystem *System) waitBackground() {
computeSystem.waitError = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
computeSystem.closedWaitOnce.Do(func() {
close(computeSystem.waitBlock)
})
}
// Wait synchronously waits for the compute system to shutdown or terminate. If
// the compute system has already exited returns the previous error (if any).
func (computeSystem *System) Wait() (err error) {
operation := "hcsshim::ComputeSystem::Wait"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
if err != nil {
return makeSystemError(computeSystem, "Wait", "", err, nil)
<-computeSystem.waitBlock
if computeSystem.waitError != nil {
return makeSystemError(computeSystem, "Wait", "", computeSystem.waitError, nil)
}
return nil
}
// WaitExpectedError synchronously waits for the compute system to shutdown or
// terminate, and ignores the passed error if it occurs.
// terminate and returns the error (if any) as long as it does not match
// `expected`. If the compute system has already exited returns the previous
// error (if any) as long as it does not match `expected`.
func (computeSystem *System) WaitExpectedError(expected error) (err error) {
operation := "hcsshim::ComputeSystem::WaitExpectedError"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
if err != nil && getInnerError(err) != expected {
return makeSystemError(computeSystem, "WaitExpectedError", "", err, nil)
<-computeSystem.waitBlock
if computeSystem.waitError != nil && getInnerError(computeSystem.waitError) != expected {
return makeSystemError(computeSystem, "WaitExpectedError", "", computeSystem.waitError, nil)
}
return nil
}
// WaitTimeout synchronously waits for the compute system to terminate or the duration to elapse.
// If the timeout expires, IsTimeout(err) == true
// WaitTimeout synchronously waits for the compute system to terminate or the
// duration to elapse. If the timeout expires, `IsTimeout(err) == true`. If
// the compute system has already exited returns the previous error (if any).
func (computeSystem *System) WaitTimeout(timeout time.Duration) (err error) {
operation := "hcsshim::ComputeSystem::WaitTimeout"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, &timeout)
if err != nil {
return makeSystemError(computeSystem, "WaitTimeout", "", err, nil)
select {
case <-computeSystem.waitBlock:
if computeSystem.waitError != nil {
return makeSystemError(computeSystem, "WaitTimeout", "", computeSystem.waitError, nil)
}
return nil
case <-time.After(timeout):
return makeSystemError(computeSystem, "WaitTimeout", "", ErrTimeout, nil)
}
}
func (computeSystem *System) Properties(types ...schema1.PropertyType) (_ *schema1.ContainerProperties, err error) {
@ -519,6 +546,7 @@ func (computeSystem *System) CreateProcess(c interface{}) (_ *Process, err error
if err = process.registerCallback(); err != nil {
return nil, makeSystemError(computeSystem, "CreateProcess", "", err, nil)
}
go process.waitBackground()
return process, nil
}
@ -557,6 +585,7 @@ func (computeSystem *System) OpenProcess(pid int) (_ *Process, err error) {
if err = process.registerCallback(); err != nil {
return nil, makeSystemError(computeSystem, "OpenProcess", "", err, nil)
}
go process.waitBackground()
return process, nil
}
@ -587,6 +616,9 @@ func (computeSystem *System) Close() (err error) {
}
computeSystem.handle = 0
computeSystem.closedWaitOnce.Do(func() {
close(computeSystem.waitBlock)
})
return nil
}
@ -640,7 +672,7 @@ func (computeSystem *System) unregisterCallback() error {
closeChannels(context.channels)
callbackMapLock.Lock()
callbackMap[callbackNumber] = nil
delete(callbackMap, callbackNumber)
callbackMapLock.Unlock()
handle = 0

View File

@ -17,6 +17,11 @@ func processAsyncHcsResult(err error, resultp *uint16, callbackNumber uintptr, e
func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error {
callbackMapLock.RLock()
if _, ok := callbackMap[callbackNumber]; !ok {
callbackMapLock.RUnlock()
logrus.Errorf("failed to waitForNotification: callbackNumber %d does not exist in callbackMap", callbackNumber)
return ErrHandleClose
}
channels := callbackMap[callbackNumber].channels
callbackMapLock.RUnlock()

View File

@ -2,9 +2,9 @@ package hns
import (
"encoding/json"
"net"
"errors"
"github.com/sirupsen/logrus"
"net"
)
// Subnet is assoicated with a network and represents a list
@ -98,6 +98,12 @@ func (network *HNSNetwork) Create() (*HNSNetwork, error) {
title := "hcsshim::HNSNetwork::" + operation
logrus.Debugf(title+" id=%s", network.Id)
for _, subnet := range network.Subnets {
if (subnet.AddressPrefix != "") && (subnet.GatewayAddress == "") {
return nil, errors.New("network create error, subnet has address prefix but no gateway specified")
}
}
jsonString, err := json.Marshal(network)
if err != nil {
return nil, err

View File

@ -10,7 +10,6 @@
package hcsschema
type Plan9Share struct {
Name string `json:"Name,omitempty"`
// The name by which the guest operation system can access this share, via the aname parameter in the Plan9 protocol.
@ -30,4 +29,6 @@ type Plan9Share struct {
ReadOnly bool `json:"ReadOnly,omitempty"`
UseShareRootIdentity bool `json:"UseShareRootIdentity,omitempty"`
AllowedFiles []string `json:"AllowedFiles,omitempty"`
}

View File

@ -1,13 +1,20 @@
github.com/blang/semver v3.1.0
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
github.com/containerd/containerd faec567304bbdf6864b1663d4f813641b5880a4a
github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
github.com/containerd/ttrpc 2a805f71863501300ae1976d29f0454ae003e85a
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
github.com/gogo/protobuf v1.0.0
github.com/golang/protobuf v1.1.0
github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55
github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f
github.com/konsorten/go-windows-terminal-sequences v1.0.1
github.com/linuxkit/virtsock 8e79449dea0735c1c056d814934dd035734cc97c
github.com/Microsoft/go-winio 16cfc975803886a5e47c4257a24c8d8c52e178b2
github.com/Microsoft/go-winio c599b533b43b1363d7d7c6cfda5ede70ed73ff13
github.com/Microsoft/opengcs v0.3.9
github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353
github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7
github.com/opencontainers/runc 12f6a991201fdb8f82579582d5e00e28fba06d0a
github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4
github.com/opencontainers/runtime-tools 1d69bd0f9c39677d0630e50664fbc3154ae61b88
github.com/pkg/errors v0.8.1
github.com/sirupsen/logrus v1.3.0
@ -17,5 +24,10 @@ github.com/xeipuuv/gojsonpointer 4e3ac2762d5f479393488629ee9370b50873b3a6
github.com/xeipuuv/gojsonreference bd5ef7bd5415a7ac448318e64f11a24cd21e594b
github.com/xeipuuv/gojsonschema 1d523034197ff1f222f6429836dd36a2457a1874
golang.org/x/crypto ff983b9c42bc9fbf91556e191cc8efb585c16908
golang.org/x/net ed066c81e75eba56dd9bd2139ade88125b855585
golang.org/x/sync 37e7f081c4d4c64e13b10787722085407fe5d15f
golang.org/x/sys e5ecc2a6747ce8d4af18ed98b3de5ae30eb3a5bb
golang.org/x/text d14c52b222ee852cdba8b07206ca0c614b389876
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
google.golang.org/grpc v1.12.0
k8s.io/kubernetes v1.13.0

View File

@ -54,7 +54,7 @@ type Config struct {
Env []string // List of environment variable to set in the container
Cmd strslice.StrSlice // Command to run when starting the container
Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (Windows specific)
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (meaning treat as a command line) (Windows specific).
Image string // Name of the image as it was passed by the operator (e.g. could be symbolic)
Volumes map[string]struct{} // List of volumes (mounts) used for the container
WorkingDir string // Current directory (PWD) in the command will be launched

View File

@ -209,6 +209,8 @@ type Info struct {
Managers int `json:",omitempty"`
Cluster *ClusterInfo `json:",omitempty"`
Warnings []string `json:",omitempty"`
}
// Peer represents a peer.

View File

@ -102,6 +102,11 @@ func parseRemoteURL(remoteURL string) (gitRepo, error) {
u.Fragment = ""
repo.remote = u.String()
}
if strings.HasPrefix(repo.ref, "-") {
return gitRepo{}, errors.Errorf("invalid refspec: %s", repo.ref)
}
return repo, nil
}
@ -124,7 +129,7 @@ func fetchArgs(remoteURL string, ref string) []string {
args = append(args, "--depth", "1")
}
return append(args, "origin", ref)
return append(args, "origin", "--", ref)
}
// Check if a given git URL supports a shallow git clone,

View File

@ -11,10 +11,6 @@ func (cli *Client) BuildCancel(ctx context.Context, id string) error {
query.Set("id", id)
serverResp, err := cli.post(ctx, "/build/cancel", query, nil, nil)
if err != nil {
ensureReaderClosed(serverResp)
return err
}
defer ensureReaderClosed(serverResp)
return nil
}

View File

@ -31,11 +31,11 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePru
query.Set("filters", filters)
serverResp, err := cli.post(ctx, "/build/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return nil, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
return nil, fmt.Errorf("Error retrieving disk usage: %v", err)

View File

@ -18,11 +18,11 @@ func (cli *Client) CheckpointList(ctx context.Context, container string, options
}
resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return checkpoints, wrapResponseError(err, resp, "container", container)
}
err = json.NewDecoder(resp.body).Decode(&checkpoints)
ensureReaderClosed(resp)
return checkpoints, err
}

View File

@ -15,11 +15,11 @@ func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (t
return response, err
}
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}

View File

@ -18,10 +18,10 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C
return swarm.Config{}, nil, err
}
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return swarm.Config{}, nil, wrapResponseError(err, resp, "config", id)
}
defer ensureReaderClosed(resp)
body, err := ioutil.ReadAll(resp.body)
if err != nil {

View File

@ -27,12 +27,12 @@ func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptio
}
resp, err := cli.get(ctx, "/configs", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var configs []swarm.Config
err = json.NewDecoder(resp.body).Decode(&configs)
ensureReaderClosed(resp)
return configs, err
}

View File

@ -8,6 +8,6 @@ func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
return err
}
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "config", id)
}

View File

@ -45,11 +45,11 @@ func (cli *Client) ContainerCommit(ctx context.Context, container string, option
var response types.IDResponse
resp, err := cli.post(ctx, "/commit", query, options.Config, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}

View File

@ -21,10 +21,10 @@ func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path stri
urlStr := "/containers/" + containerID + "/archive"
response, err := cli.head(ctx, urlStr, query, nil)
defer ensureReaderClosed(response)
if err != nil {
return types.ContainerPathStat{}, wrapResponseError(err, response, "container:path", containerID+":"+path)
}
defer ensureReaderClosed(response)
return getContainerPathStatFromHeader(response.header)
}
@ -45,10 +45,10 @@ func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath str
apiPath := "/containers/" + containerID + "/archive"
response, err := cli.putRaw(ctx, apiPath, query, content, nil)
defer ensureReaderClosed(response)
if err != nil {
return wrapResponseError(err, response, "container:path", containerID+":"+dstPath)
}
defer ensureReaderClosed(response)
// TODO this code converts non-error status-codes (e.g., "204 No Content") into an error; verify if this is the desired behavior
if response.statusCode != http.StatusOK {

View File

@ -42,11 +42,11 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
}
serverResp, err := cli.post(ctx, "/containers/create", query, body, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return response, err
}
err = json.NewDecoder(serverResp.body).Decode(&response)
ensureReaderClosed(serverResp)
return response, err
}

View File

@ -13,11 +13,11 @@ func (cli *Client) ContainerDiff(ctx context.Context, containerID string) ([]con
var changes []container.ContainerChangeResponseItem
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return changes, err
}
err = json.NewDecoder(serverResp.body).Decode(&changes)
ensureReaderClosed(serverResp)
return changes, err
}

View File

@ -16,11 +16,11 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, container string, co
}
resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, config, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}

View File

@ -16,10 +16,10 @@ func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (ty
return types.ContainerJSON{}, objectNotFoundError{object: "container", id: containerID}
}
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return types.ContainerJSON{}, wrapResponseError(err, serverResp, "container", containerID)
}
defer ensureReaderClosed(serverResp)
var response types.ContainerJSON
err = json.NewDecoder(serverResp.body).Decode(&response)
@ -36,10 +36,10 @@ func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID stri
query.Set("size", "1")
}
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return types.ContainerJSON{}, nil, wrapResponseError(err, serverResp, "container", containerID)
}
defer ensureReaderClosed(serverResp)
body, err := ioutil.ReadAll(serverResp.body)
if err != nil {

View File

@ -45,12 +45,12 @@ func (cli *Client) ContainerList(ctx context.Context, options types.ContainerLis
}
resp, err := cli.get(ctx, "/containers/json", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var containers []types.Container
err = json.NewDecoder(resp.body).Decode(&containers)
ensureReaderClosed(resp)
return containers, err
}

View File

@ -23,10 +23,10 @@ func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Arg
}
serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return report, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
return report, fmt.Errorf("Error retrieving disk usage: %v", err)

View File

@ -22,6 +22,6 @@ func (cli *Client) ContainerRemove(ctx context.Context, containerID string, opti
}
resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "container", containerID)
}

View File

@ -18,11 +18,11 @@ func (cli *Client) ContainerTop(ctx context.Context, containerID string, argumen
}
resp, err := cli.get(ctx, "/containers/"+containerID+"/top", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}

View File

@ -11,12 +11,11 @@ import (
func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error) {
var response container.ContainerUpdateOKBody
serverResp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return response, err
}
err = json.NewDecoder(serverResp.body).Decode(&response)
ensureReaderClosed(serverResp)
return response, err
}

View File

@ -13,10 +13,10 @@ func (cli *Client) DiskUsage(ctx context.Context) (types.DiskUsage, error) {
var du types.DiskUsage
serverResp, err := cli.get(ctx, "/system/df", nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return du, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&du); err != nil {
return du, fmt.Errorf("Error retrieving disk usage: %v", err)

View File

@ -28,11 +28,11 @@ func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegist
}
resp, err := cli.get(ctx, "/distribution/"+image+"/json", url.Values{}, headers)
defer ensureReaderClosed(resp)
if err != nil {
return distributionInspect, err
}
err = json.NewDecoder(resp.body).Decode(&distributionInspect)
ensureReaderClosed(resp)
return distributionInspect, err
}

View File

@ -38,6 +38,17 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
return types.HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn)}, err
}
// DialHijack returns a hijacked connection with negotiated protocol proto.
func (cli *Client) DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error) {
req, err := http.NewRequest("POST", url, nil)
if err != nil {
return nil, err
}
req = cli.addHeaders(req, meta)
return cli.setupHijackConn(ctx, req, proto)
}
// fallbackDial is used when WithDialer() was not called.
// See cli.Dialer().
func fallbackDial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) {

View File

@ -12,11 +12,11 @@ import (
func (cli *Client) ImageHistory(ctx context.Context, imageID string) ([]image.HistoryResponseItem, error) {
var history []image.HistoryResponseItem
serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", url.Values{}, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return history, err
}
err = json.NewDecoder(serverResp.body).Decode(&history)
ensureReaderClosed(serverResp)
return history, err
}

View File

@ -15,10 +15,10 @@ func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (typ
return types.ImageInspect{}, nil, objectNotFoundError{object: "image", id: imageID}
}
serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return types.ImageInspect{}, nil, wrapResponseError(err, serverResp, "image", imageID)
}
defer ensureReaderClosed(serverResp)
body, err := ioutil.ReadAll(serverResp.body)
if err != nil {

View File

@ -35,11 +35,11 @@ func (cli *Client) ImageList(ctx context.Context, options types.ImageListOptions
}
serverResp, err := cli.get(ctx, "/images/json", query, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return images, err
}
err = json.NewDecoder(serverResp.body).Decode(&images)
ensureReaderClosed(serverResp)
return images, err
}

View File

@ -23,10 +23,10 @@ func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (
}
serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return report, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
return report, fmt.Errorf("Error retrieving disk usage: %v", err)

View File

@ -21,11 +21,11 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options type
var dels []types.ImageDeleteResponseItem
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return dels, wrapResponseError(err, resp, "image", imageID)
}
err = json.NewDecoder(resp.body).Decode(&dels)
ensureReaderClosed(resp)
return dels, err
}

View File

@ -29,6 +29,7 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I
}
resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth)
defer ensureReaderClosed(resp)
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
newAuthHeader, privilegeErr := options.PrivilegeFunc()
if privilegeErr != nil {
@ -41,7 +42,6 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I
}
err = json.NewDecoder(resp.body).Decode(&results)
ensureReaderClosed(resp)
return results, err
}

View File

@ -13,10 +13,10 @@ import (
func (cli *Client) Info(ctx context.Context) (types.Info, error) {
var info types.Info
serverResp, err := cli.get(ctx, "/info", url.Values{}, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return info, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&info); err != nil {
return info, fmt.Errorf("Error reading remote info: %v", err)

View File

@ -38,7 +38,7 @@ type CommonAPIClient interface {
ServerVersion(ctx context.Context) (types.Version, error)
NegotiateAPIVersion(ctx context.Context)
NegotiateAPIVersionPing(types.Ping)
DialSession(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error)
DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error)
Dialer() func(context.Context) (net.Conn, error)
Close() error
}

View File

@ -13,6 +13,7 @@ import (
// It returns unauthorizedError when the authentication fails.
func (cli *Client) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, error) {
resp, err := cli.post(ctx, "/auth", url.Values{}, auth, nil)
defer ensureReaderClosed(resp)
if err != nil {
return registry.AuthenticateOKBody{}, err
@ -20,6 +21,5 @@ func (cli *Client) RegistryLogin(ctx context.Context, auth types.AuthConfig) (re
var response registry.AuthenticateOKBody
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}

View File

@ -15,11 +15,11 @@ func (cli *Client) NetworkCreate(ctx context.Context, name string, options types
}
var response types.NetworkCreateResponse
serverResp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return response, err
}
json.NewDecoder(serverResp.body).Decode(&response)
ensureReaderClosed(serverResp)
err = json.NewDecoder(serverResp.body).Decode(&response)
return response, err
}

View File

@ -34,10 +34,10 @@ func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string,
query.Set("scope", options.Scope)
}
resp, err = cli.get(ctx, "/networks/"+networkID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return networkResource, nil, wrapResponseError(err, resp, "network", networkID)
}
defer ensureReaderClosed(resp)
body, err := ioutil.ReadAll(resp.body)
if err != nil {

View File

@ -22,10 +22,10 @@ func (cli *Client) NetworkList(ctx context.Context, options types.NetworkListOpt
}
var networkResources []types.NetworkResource
resp, err := cli.get(ctx, "/networks", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return networkResources, err
}
err = json.NewDecoder(resp.body).Decode(&networkResources)
ensureReaderClosed(resp)
return networkResources, err
}

View File

@ -23,10 +23,10 @@ func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args)
}
serverResp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return report, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
return report, fmt.Errorf("Error retrieving network prune report: %v", err)

View File

@ -5,6 +5,6 @@ import "context"
// NetworkRemove removes an existent network from the docker host.
func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error {
resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "network", networkID)
}

View File

@ -15,10 +15,10 @@ func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm
return swarm.Node{}, nil, objectNotFoundError{object: "node", id: nodeID}
}
serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return swarm.Node{}, nil, wrapResponseError(err, serverResp, "node", nodeID)
}
defer ensureReaderClosed(serverResp)
body, err := ioutil.ReadAll(serverResp.body)
if err != nil {

View File

@ -25,12 +25,12 @@ func (cli *Client) NodeList(ctx context.Context, options types.NodeListOptions)
}
resp, err := cli.get(ctx, "/nodes", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var nodes []swarm.Node
err = json.NewDecoder(resp.body).Decode(&nodes)
ensureReaderClosed(resp)
return nodes, err
}

View File

@ -15,6 +15,6 @@ func (cli *Client) NodeRemove(ctx context.Context, nodeID string, options types.
}
resp, err := cli.delete(ctx, "/nodes/"+nodeID, query, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "node", nodeID)
}

View File

@ -45,8 +45,9 @@ func FromEnv(c *Client) error {
}
if version := os.Getenv("DOCKER_API_VERSION"); version != "" {
c.version = version
c.manualOverride = true
if err := WithVersion(version)(c); err != nil {
return err
}
}
return nil
}
@ -139,6 +140,7 @@ func WithTLSClientConfig(cacertPath, certPath, keyPath string) func(*Client) err
func WithVersion(version string) func(*Client) error {
return func(c *Client) error {
c.version = version
c.manualOverride = true
return nil
}
}

View File

@ -38,10 +38,10 @@ func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
return ping, err
}
serverResp, err = cli.doRequest(ctx, req)
defer ensureReaderClosed(serverResp)
if err != nil {
return ping, err
}
defer ensureReaderClosed(serverResp)
return parsePingResponse(cli, serverResp)
}

View File

@ -18,9 +18,6 @@ func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, cr
query.Set("name", createOptions.RepoName)
resp, err := cli.postRaw(ctx, "/plugins/create", query, createContext, headers)
if err != nil {
return err
}
ensureReaderClosed(resp)
return err
}

View File

@ -15,11 +15,11 @@ func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*type
return nil, nil, objectNotFoundError{object: "plugin", id: name}
}
resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, nil, wrapResponseError(err, resp, "plugin", name)
}
defer ensureReaderClosed(resp)
body, err := ioutil.ReadAll(resp.body)
if err != nil {
return nil, nil, err

View File

@ -22,11 +22,11 @@ func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (types.P
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/plugins", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return plugins, wrapResponseError(err, resp, "plugin", "")
}
err = json.NewDecoder(resp.body).Decode(&plugins)
ensureReaderClosed(resp)
return plugins, err
}

View File

@ -15,6 +15,6 @@ func (cli *Client) PluginRemove(ctx context.Context, name string, options types.
}
resp, err := cli.delete(ctx, "/plugins/"+name, query, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "plugin", name)
}

View File

@ -15,11 +15,11 @@ func (cli *Client) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (t
return response, err
}
resp, err := cli.post(ctx, "/secrets/create", nil, secret, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}

View File

@ -18,10 +18,10 @@ func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.S
return swarm.Secret{}, nil, objectNotFoundError{object: "secret", id: id}
}
resp, err := cli.get(ctx, "/secrets/"+id, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return swarm.Secret{}, nil, wrapResponseError(err, resp, "secret", id)
}
defer ensureReaderClosed(resp)
body, err := ioutil.ReadAll(resp.body)
if err != nil {

View File

@ -27,12 +27,12 @@ func (cli *Client) SecretList(ctx context.Context, options types.SecretListOptio
}
resp, err := cli.get(ctx, "/secrets", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var secrets []swarm.Secret
err = json.NewDecoder(resp.body).Decode(&secrets)
ensureReaderClosed(resp)
return secrets, err
}

View File

@ -8,6 +8,6 @@ func (cli *Client) SecretRemove(ctx context.Context, id string) error {
return err
}
resp, err := cli.delete(ctx, "/secrets/"+id, nil, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "secret", id)
}

View File

@ -72,6 +72,7 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
var response types.ServiceCreateResponse
resp, err := cli.post(ctx, "/services/create", nil, service, headers)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
@ -82,7 +83,6 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
response.Warnings = append(response.Warnings, digestWarning(service.TaskTemplate.ContainerSpec.Image))
}
ensureReaderClosed(resp)
return response, err
}

View File

@ -20,10 +20,10 @@ func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string,
query := url.Values{}
query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults))
serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return swarm.Service{}, nil, wrapResponseError(err, serverResp, "service", serviceID)
}
defer ensureReaderClosed(serverResp)
body, err := ioutil.ReadAll(serverResp.body)
if err != nil {

View File

@ -24,12 +24,12 @@ func (cli *Client) ServiceList(ctx context.Context, options types.ServiceListOpt
}
resp, err := cli.get(ctx, "/services", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var services []swarm.Service
err = json.NewDecoder(resp.body).Decode(&services)
ensureReaderClosed(resp)
return services, err
}

View File

@ -5,6 +5,6 @@ import "context"
// ServiceRemove kills and removes a service.
func (cli *Client) ServiceRemove(ctx context.Context, serviceID string) error {
resp, err := cli.delete(ctx, "/services/"+serviceID, nil, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "service", serviceID)
}

View File

@ -79,6 +79,7 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
var response types.ServiceUpdateResponse
resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, service, headers)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
@ -89,6 +90,5 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
response.Warnings = append(response.Warnings, digestWarning(service.TaskTemplate.ContainerSpec.Image))
}
ensureReaderClosed(resp)
return response, err
}

View File

@ -1,18 +0,0 @@
package client // import "github.com/docker/docker/client"
import (
"context"
"net"
"net/http"
)
// DialSession returns a connection that can be used communication with daemon
func (cli *Client) DialSession(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) {
req, err := http.NewRequest("POST", "/session", nil)
if err != nil {
return nil, err
}
req = cli.addHeaders(req, meta)
return cli.setupHijackConn(ctx, req, proto)
}

View File

@ -10,12 +10,12 @@ import (
// SwarmGetUnlockKey retrieves the swarm's unlock key.
func (cli *Client) SwarmGetUnlockKey(ctx context.Context) (types.SwarmUnlockKeyResponse, error) {
serverResp, err := cli.get(ctx, "/swarm/unlockkey", nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return types.SwarmUnlockKeyResponse{}, err
}
var response types.SwarmUnlockKeyResponse
err = json.NewDecoder(serverResp.body).Decode(&response)
ensureReaderClosed(serverResp)
return response, err
}

View File

@ -10,12 +10,12 @@ import (
// SwarmInit initializes the swarm.
func (cli *Client) SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) {
serverResp, err := cli.post(ctx, "/swarm/init", nil, req, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return "", err
}
var response string
err = json.NewDecoder(serverResp.body).Decode(&response)
ensureReaderClosed(serverResp)
return response, err
}

View File

@ -10,12 +10,12 @@ import (
// SwarmInspect inspects the swarm.
func (cli *Client) SwarmInspect(ctx context.Context) (swarm.Swarm, error) {
serverResp, err := cli.get(ctx, "/swarm", nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return swarm.Swarm{}, err
}
var response swarm.Swarm
err = json.NewDecoder(serverResp.body).Decode(&response)
ensureReaderClosed(serverResp)
return response, err
}

View File

@ -15,10 +15,10 @@ func (cli *Client) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm
return swarm.Task{}, nil, objectNotFoundError{object: "task", id: taskID}
}
serverResp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return swarm.Task{}, nil, wrapResponseError(err, serverResp, "task", taskID)
}
defer ensureReaderClosed(serverResp)
body, err := ioutil.ReadAll(serverResp.body)
if err != nil {

View File

@ -24,12 +24,12 @@ func (cli *Client) TaskList(ctx context.Context, options types.TaskListOptions)
}
resp, err := cli.get(ctx, "/tasks", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var tasks []swarm.Task
err = json.NewDecoder(resp.body).Decode(&tasks)
ensureReaderClosed(resp)
return tasks, err
}

View File

@ -10,12 +10,12 @@ import (
// ServerVersion returns information of the docker client and server host.
func (cli *Client) ServerVersion(ctx context.Context) (types.Version, error) {
resp, err := cli.get(ctx, "/version", nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return types.Version{}, err
}
var server types.Version
err = json.NewDecoder(resp.body).Decode(&server)
ensureReaderClosed(resp)
return server, err
}

View File

@ -12,10 +12,10 @@ import (
func (cli *Client) VolumeCreate(ctx context.Context, options volumetypes.VolumeCreateBody) (types.Volume, error) {
var volume types.Volume
resp, err := cli.post(ctx, "/volumes/create", nil, options, nil)
defer ensureReaderClosed(resp)
if err != nil {
return volume, err
}
err = json.NewDecoder(resp.body).Decode(&volume)
ensureReaderClosed(resp)
return volume, err
}

View File

@ -23,10 +23,10 @@ func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (t
var volume types.Volume
resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return volume, nil, wrapResponseError(err, resp, "volume", volumeID)
}
defer ensureReaderClosed(resp)
body, err := ioutil.ReadAll(resp.body)
if err != nil {

View File

@ -22,11 +22,11 @@ func (cli *Client) VolumeList(ctx context.Context, filter filters.Args) (volumet
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/volumes", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return volumes, err
}
err = json.NewDecoder(resp.body).Decode(&volumes)
ensureReaderClosed(resp)
return volumes, err
}

View File

@ -23,10 +23,10 @@ func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args)
}
serverResp, err := cli.post(ctx, "/volumes/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return report, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
return report, fmt.Errorf("Error retrieving volume prune report: %v", err)

View File

@ -16,6 +16,6 @@ func (cli *Client) VolumeRemove(ctx context.Context, volumeID string, force bool
}
}
resp, err := cli.delete(ctx, "/volumes/"+volumeID, query, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "volume", volumeID)
}

View File

@ -43,11 +43,6 @@ type ErrNotModified interface {
NotModified()
}
// ErrAlreadyExists is a special case of ErrConflict which signals that the desired object already exists
type ErrAlreadyExists interface {
AlreadyExists()
}
// ErrNotImplemented signals that the requested action/feature is not implemented on the system as configured.
type ErrNotImplemented interface {
NotImplemented()

View File

@ -130,22 +130,6 @@ func NotModified(err error) error {
return errNotModified{err}
}
type errAlreadyExists struct{ error }
func (errAlreadyExists) AlreadyExists() {}
func (e errAlreadyExists) Cause() error {
return e.error
}
// AlreadyExists is a helper to create an error of the class with the same name from any error type
func AlreadyExists(err error) error {
if err == nil || IsAlreadyExists(err) {
return err
}
return errAlreadyExists{err}
}
type errNotImplemented struct{ error }
func (errNotImplemented) NotImplemented() {}

View File

@ -28,7 +28,7 @@ func GetHTTPErrorStatusCode(err error) int {
statusCode = http.StatusNotFound
case IsInvalidParameter(err):
statusCode = http.StatusBadRequest
case IsConflict(err) || IsAlreadyExists(err):
case IsConflict(err):
statusCode = http.StatusConflict
case IsUnauthorized(err):
statusCode = http.StatusUnauthorized

View File

@ -15,7 +15,6 @@ func getImplementer(err error) error {
ErrForbidden,
ErrSystem,
ErrNotModified,
ErrAlreadyExists,
ErrNotImplemented,
ErrCancelled,
ErrDeadline,
@ -77,12 +76,6 @@ func IsNotModified(err error) bool {
return ok
}
// IsAlreadyExists returns if the passed in error is a AlreadyExists error
func IsAlreadyExists(err error) bool {
_, ok := getImplementer(err).(ErrAlreadyExists)
return ok
}
// IsNotImplemented returns if the passed in error is an ErrNotImplemented
func IsNotImplemented(err error) bool {
_, ok := getImplementer(err).(ErrNotImplemented)

View File

@ -7,16 +7,21 @@ import (
"os"
"strconv"
"strings"
"github.com/pkg/errors"
)
func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
s := bufio.NewScanner(r)
out := []*Info{}
var err error
for s.Scan() {
if err := s.Err(); err != nil {
if err = s.Err(); err != nil {
return nil, err
}
/*
See http://man7.org/linux/man-pages/man5/proc.5.html
36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
@ -52,8 +57,15 @@ func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
p.Major, _ = strconv.Atoi(mm[0])
p.Minor, _ = strconv.Atoi(mm[1])
p.Root = fields[3]
p.Mountpoint = fields[4]
p.Root, err = strconv.Unquote(`"` + fields[3] + `"`)
if err != nil {
return nil, errors.Wrapf(err, "Parsing '%s' failed: unable to unquote root field", fields[3])
}
p.Mountpoint, err = strconv.Unquote(`"` + fields[4] + `"`)
if err != nil {
return nil, errors.Wrapf(err, "Parsing '%s' failed: unable to unquote mount point field", fields[4])
}
p.Opts = fields[5]
var skip, stop bool

View File

@ -0,0 +1,16 @@
package system // import "github.com/docker/docker/pkg/system"
import (
"strings"
"golang.org/x/sys/windows"
)
// EscapeArgs makes a Windows-style escaped command line from a set of arguments
func EscapeArgs(args []string) string {
escapedArgs := make([]string, len(args))
for i, a := range args {
escapedArgs[i] = windows.EscapeArg(a)
}
return strings.Join(escapedArgs, " ")
}

View File

@ -18,8 +18,6 @@ import (
const (
// SddlAdministratorsLocalSystem is local administrators plus NT AUTHORITY\System
SddlAdministratorsLocalSystem = "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)"
// SddlNtvmAdministratorsLocalSystem is NT VIRTUAL MACHINE\Virtual Machines plus local administrators plus NT AUTHORITY\System
SddlNtvmAdministratorsLocalSystem = "D:P(A;OICI;GA;;;S-1-5-83-0)(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)"
)
// MkdirAllWithACL is a wrapper for MkdirAll that creates a directory

View File

@ -5,3 +5,8 @@ package system // import "github.com/docker/docker/pkg/system"
// InitLCOW does nothing since LCOW is a windows only feature
func InitLCOW(experimental bool) {
}
// ContainerdRuntimeSupported returns true if the use of ContainerD runtime is supported.
func ContainerdRuntimeSupported(_ bool, _ string) bool {
return true
}

View File

@ -1,7 +1,19 @@
package system // import "github.com/docker/docker/pkg/system"
import (
"os"
"github.com/sirupsen/logrus"
)
var (
// lcowSupported determines if Linux Containers on Windows are supported.
var lcowSupported = false
lcowSupported = false
// containerdRuntimeSupported determines if ContainerD should be the runtime.
// As of March 2019, this is an experimental feature.
containerdRuntimeSupported = false
)
// InitLCOW sets whether LCOW is supported or not
func InitLCOW(experimental bool) {
@ -10,3 +22,19 @@ func InitLCOW(experimental bool) {
lcowSupported = true
}
}
// InitContainerdRuntime sets whether to use ContainerD for runtime
// on Windows. This is an experimental feature still in development, and
// also requires an environment variable to be set (so as not to turn the
// feature on from simply experimental which would also mean LCOW.
func InitContainerdRuntime(experimental bool, cdPath string) {
if experimental && len(cdPath) > 0 && len(os.Getenv("DOCKER_WINDOWS_CONTAINERD_RUNTIME")) > 0 {
logrus.Warnf("Using ContainerD runtime. This feature is experimental")
containerdRuntimeSupported = true
}
}
// ContainerdRuntimeSupported returns true if the use of ContainerD runtime is supported.
func ContainerdRuntimeSupported() bool {
return containerdRuntimeSupported
}

View File

@ -248,7 +248,6 @@ func (err PingResponseError) Error() string {
// challenge manager for the supported authentication types and
// whether v2 was confirmed by the response. If a response is received but
// cannot be interpreted a PingResponseError will be returned.
// nolint: interfacer
func PingV2Registry(endpoint *url.URL, transport http.RoundTripper) (challenge.Manager, bool, error) {
var (
foundV2 = false

View File

@ -1,16 +1,17 @@
# the following lines are in sorted order, FYI
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
github.com/Microsoft/hcsshim v0.8.6
github.com/Microsoft/go-winio v0.4.11
github.com/Microsoft/hcsshim ba3d6667710fa905116f39a19d059c4c1016be7c
github.com/Microsoft/go-winio c599b533b43b1363d7d7c6cfda5ede70ed73ff13
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git
github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a
github.com/google/uuid v1.1.1
github.com/gorilla/mux v1.7.0
github.com/Microsoft/opengcs v0.3.9
github.com/Microsoft/opengcs a10967154e143a36014584a6f664344e3bb0aa64
github.com/konsorten/go-windows-terminal-sequences v1.0.1
github.com/kr/pty 5cf931ef8f
github.com/mattn/go-shellwords v1.0.3
github.com/sirupsen/logrus v1.0.6
github.com/sirupsen/logrus v1.3.0
github.com/tchap/go-patricia v2.2.6
github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
golang.org/x/net a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1
@ -26,8 +27,8 @@ github.com/imdario/mergo v0.3.6
golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca
# buildkit
github.com/moby/buildkit c35410878ab9070498c66f6c67d3e8bc3b92241f
github.com/tonistiigi/fsutil 1ec1983587cde7e8ac2978e354ff5360af622464
github.com/moby/buildkit b3028967ae6259c9a31c1a1deeccd30fe3469cce
github.com/tonistiigi/fsutil 3bbb99cdbd76619ab717299830c60f6f2a533a6b
github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
github.com/google/shlex 6f45313302b9c56850fc17f99e40caebce98c716
@ -38,7 +39,7 @@ github.com/gofrs/flock 7f43ea2e6a643ad441fc12d0ecc0d3388b300c53 # v0.7.0
#get libnetwork packages
# When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly
github.com/docker/libnetwork 1a06131fb8a047d919f7deaf02a4c414d7884b83
github.com/docker/libnetwork ebcade70ad1059b070d0040d798ecca359bc5fed
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
@ -119,10 +120,10 @@ github.com/googleapis/gax-go v2.0.0
google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
# containerd
github.com/containerd/containerd a15b6e2097c48b632dbdc63254bad4c62b69e709
github.com/containerd/containerd ceba56893a76f22cf0126c46d835c80fb3833408
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d
github.com/containerd/cgroups dbea6f2bd41658b84b00417ceefa416b979cbf10
github.com/containerd/cgroups 4994991857f9b0ae8dc439551e8bebdbb4bf66c1
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
@ -130,12 +131,12 @@ github.com/containerd/ttrpc f02858b1457c5ca3aaec3a0803eb0d59f96e41d6
github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
# cluster
github.com/docker/swarmkit 415dc72789e2b733ea884f09188c286ca187d8ec
github.com/docker/swarmkit 18e7e58ea1a5ec016625a636d0d52500eea123bc
github.com/gogo/protobuf v1.2.0
github.com/cloudflare/cfssl 1.3.2
github.com/fernet/fernet-go 1b2437bc582b3cfbb341ee5a29f8ef5b42912ff2
github.com/google/certificate-transparency-go v1.0.20
golang.org/x/crypto 0709b304e793a5edb4a2c0145f281ecdc20838a4
golang.org/x/crypto b7391e95e576cacdcdd422573063bc057239113d
golang.org/x/time fbb02b2291d28baffd63558aa44b4b56f178d650
github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad
github.com/hashicorp/go-immutable-radix 826af9ccf0feeee615d546d69b11f8e98da8c8f1 git://github.com/tonistiigi/go-immutable-radix.git
@ -160,4 +161,4 @@ github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b
# metrics
github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
github.com/opencontainers/selinux b6fa367ed7f534f9ba25391cc2d467085dbb445a
github.com/opencontainers/selinux 9e2c5215628a2567782777efb2049f385484f918 # v1.2

View File

@ -0,0 +1,9 @@
(The MIT License)
Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,40 @@
# Windows Terminal Sequences
This library allow for enabling Windows terminal color support for Go.
See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details.
## Usage
```go
import (
"syscall"
sequences "github.com/konsorten/go-windows-terminal-sequences"
)
func main() {
sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true)
}
```
## Authors
The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
We thank all the authors who provided code to this library:
* Felix Kollmann
## License
(The MIT License)
Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,36 @@
// +build windows
package sequences
import (
"syscall"
"unsafe"
)
var (
kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll")
setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode")
)
func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4
var mode uint32
err := syscall.GetConsoleMode(syscall.Stdout, &mode)
if err != nil {
return err
}
if enable {
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
} else {
mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING
}
ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode))
if ret == 0 {
return err
}
return nil
}

View File

@ -56,8 +56,39 @@ time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
exit status 1
```
To ensure this behaviour even if a TTY is attached, set your formatter as follows:
```go
log.SetFormatter(&log.TextFormatter{
DisableColors: true,
FullTimestamp: true,
})
```
#### Logging Method Name
If you wish to add the calling method as a field, instruct the logger via:
```go
log.SetReportCaller(true)
```
This adds the caller as 'method' like so:
```json
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by",
"time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
```
```text
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
```
Note that this does add measurable overhead - the cost will depend on the version of Go, but is
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
environment via benchmarks:
```
go test -bench=.*CallerTracing
```
#### Case-sensitivity
@ -246,9 +277,10 @@ A list of currently known of service hook can be found in this wiki [page](https
#### Level logging
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.
```go
log.Trace("Something very low level.")
log.Debug("Useful debugging information.")
log.Info("Something noteworthy happened!")
log.Warn("You should probably take a look at this.")
@ -329,6 +361,7 @@ The built-in logging formatters are:
Third party logging formatters:
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html).
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.

View File

@ -4,11 +4,30 @@ import (
"bytes"
"fmt"
"os"
"reflect"
"runtime"
"strings"
"sync"
"time"
)
var bufferPool *sync.Pool
var (
bufferPool *sync.Pool
// qualified package name, cached at first use
logrusPackage string
// Positions in the call stack when tracing to report the calling method
minimumCallerDepth int
// Used for caller information initialisation
callerInitOnce sync.Once
)
const (
maximumCallerDepth int = 25
knownLogrusFrames int = 4
)
func init() {
bufferPool = &sync.Pool{
@ -16,15 +35,18 @@ func init() {
return new(bytes.Buffer)
},
}
// start at the bottom of the stack before the package-name cache is primed
minimumCallerDepth = 1
}
// Defines the key when adding errors using WithError.
var ErrorKey = "error"
// An entry is the final or intermediate Logrus logging entry. It contains all
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
// passed around as much as you wish to avoid field duplication.
// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
// reused and passed around as much as you wish to avoid field duplication.
type Entry struct {
Logger *Logger
@ -34,22 +56,28 @@ type Entry struct {
// Time at which the log entry was created
Time time.Time
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
Level Level
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
// Calling method, with package name
Caller *runtime.Frame
// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
Message string
// When formatter is called in entry.log(), an Buffer may be set to entry
// When formatter is called in entry.log(), a Buffer may be set to entry
Buffer *bytes.Buffer
// err may contain a field formatting error
err string
}
func NewEntry(logger *Logger) *Entry {
return &Entry{
Logger: logger,
// Default is five fields, give a little extra room
Data: make(Fields, 5),
// Default is three fields, plus one optional. Give a little extra room.
Data: make(Fields, 6),
}
}
@ -80,15 +108,85 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
for k, v := range entry.Data {
data[k] = v
}
fieldErr := entry.err
for k, v := range fields {
isErrField := false
if t := reflect.TypeOf(v); t != nil {
switch t.Kind() {
case reflect.Func:
isErrField = true
case reflect.Ptr:
isErrField = t.Elem().Kind() == reflect.Func
}
}
if isErrField {
tmp := fmt.Sprintf("can not add field %q", k)
if fieldErr != "" {
fieldErr = entry.err + ", " + tmp
} else {
fieldErr = tmp
}
} else {
data[k] = v
}
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time}
}
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr}
}
// Overrides the time of the Entry.
func (entry *Entry) WithTime(t time.Time) *Entry {
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t}
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err}
}
// getPackageName reduces a fully qualified function name to the package name
// There really ought to be to be a better way...
func getPackageName(f string) string {
for {
lastPeriod := strings.LastIndex(f, ".")
lastSlash := strings.LastIndex(f, "/")
if lastPeriod > lastSlash {
f = f[:lastPeriod]
} else {
break
}
}
return f
}
// getCaller retrieves the name of the first non-logrus calling function
func getCaller() *runtime.Frame {
// Restrict the lookback frames to avoid runaway lookups
pcs := make([]uintptr, maximumCallerDepth)
depth := runtime.Callers(minimumCallerDepth, pcs)
frames := runtime.CallersFrames(pcs[:depth])
// cache this package's fully-qualified name
callerInitOnce.Do(func() {
logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name())
// now that we have the cache, we can skip a minimum count of known-logrus functions
// XXX this is dubious, the number of frames may vary store an entry in a logger interface
minimumCallerDepth = knownLogrusFrames
})
for f, again := frames.Next(); again; f, again = frames.Next() {
pkg := getPackageName(f.Function)
// If the caller isn't part of this package, we're done
if pkg != logrusPackage {
return &f
}
}
// if we got here, we failed to find the caller's context
return nil
}
func (entry Entry) HasCaller() (has bool) {
return entry.Logger != nil &&
entry.Logger.ReportCaller &&
entry.Caller != nil
}
// This function is not declared with a pointer value because otherwise
@ -107,6 +205,9 @@ func (entry Entry) log(level Level, msg string) {
entry.Level = level
entry.Message = msg
if entry.Logger.ReportCaller {
entry.Caller = getCaller()
}
entry.fireHooks()
@ -137,9 +238,9 @@ func (entry *Entry) fireHooks() {
}
func (entry *Entry) write() {
serialized, err := entry.Logger.Formatter.Format(entry)
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
serialized, err := entry.Logger.Formatter.Format(entry)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
} else {
@ -150,26 +251,30 @@ func (entry *Entry) write() {
}
}
func (entry *Entry) Debug(args ...interface{}) {
if entry.Logger.level() >= DebugLevel {
entry.log(DebugLevel, fmt.Sprint(args...))
func (entry *Entry) Log(level Level, args ...interface{}) {
if entry.Logger.IsLevelEnabled(level) {
entry.log(level, fmt.Sprint(args...))
}
}
func (entry *Entry) Trace(args ...interface{}) {
entry.Log(TraceLevel, args...)
}
func (entry *Entry) Debug(args ...interface{}) {
entry.Log(DebugLevel, args...)
}
func (entry *Entry) Print(args ...interface{}) {
entry.Info(args...)
}
func (entry *Entry) Info(args ...interface{}) {
if entry.Logger.level() >= InfoLevel {
entry.log(InfoLevel, fmt.Sprint(args...))
}
entry.Log(InfoLevel, args...)
}
func (entry *Entry) Warn(args ...interface{}) {
if entry.Logger.level() >= WarnLevel {
entry.log(WarnLevel, fmt.Sprint(args...))
}
entry.Log(WarnLevel, args...)
}
func (entry *Entry) Warning(args ...interface{}) {
@ -177,37 +282,35 @@ func (entry *Entry) Warning(args ...interface{}) {
}
func (entry *Entry) Error(args ...interface{}) {
if entry.Logger.level() >= ErrorLevel {
entry.log(ErrorLevel, fmt.Sprint(args...))
}
entry.Log(ErrorLevel, args...)
}
func (entry *Entry) Fatal(args ...interface{}) {
if entry.Logger.level() >= FatalLevel {
entry.log(FatalLevel, fmt.Sprint(args...))
}
Exit(1)
entry.Log(FatalLevel, args...)
entry.Logger.Exit(1)
}
func (entry *Entry) Panic(args ...interface{}) {
if entry.Logger.level() >= PanicLevel {
entry.log(PanicLevel, fmt.Sprint(args...))
}
entry.Log(PanicLevel, args...)
panic(fmt.Sprint(args...))
}
// Entry Printf family functions
func (entry *Entry) Debugf(format string, args ...interface{}) {
if entry.Logger.level() >= DebugLevel {
entry.Debug(fmt.Sprintf(format, args...))
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
entry.Log(level, fmt.Sprintf(format, args...))
}
func (entry *Entry) Tracef(format string, args ...interface{}) {
entry.Logf(TraceLevel, format, args...)
}
func (entry *Entry) Debugf(format string, args ...interface{}) {
entry.Logf(DebugLevel, format, args...)
}
func (entry *Entry) Infof(format string, args ...interface{}) {
if entry.Logger.level() >= InfoLevel {
entry.Info(fmt.Sprintf(format, args...))
}
entry.Logf(InfoLevel, format, args...)
}
func (entry *Entry) Printf(format string, args ...interface{}) {
@ -215,9 +318,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) {
}
func (entry *Entry) Warnf(format string, args ...interface{}) {
if entry.Logger.level() >= WarnLevel {
entry.Warn(fmt.Sprintf(format, args...))
}
entry.Logf(WarnLevel, format, args...)
}
func (entry *Entry) Warningf(format string, args ...interface{}) {
@ -225,36 +326,36 @@ func (entry *Entry) Warningf(format string, args ...interface{}) {
}
func (entry *Entry) Errorf(format string, args ...interface{}) {
if entry.Logger.level() >= ErrorLevel {
entry.Error(fmt.Sprintf(format, args...))
}
entry.Logf(ErrorLevel, format, args...)
}
func (entry *Entry) Fatalf(format string, args ...interface{}) {
if entry.Logger.level() >= FatalLevel {
entry.Fatal(fmt.Sprintf(format, args...))
}
Exit(1)
entry.Logf(FatalLevel, format, args...)
entry.Logger.Exit(1)
}
func (entry *Entry) Panicf(format string, args ...interface{}) {
if entry.Logger.level() >= PanicLevel {
entry.Panic(fmt.Sprintf(format, args...))
}
entry.Logf(PanicLevel, format, args...)
}
// Entry Println family functions
func (entry *Entry) Debugln(args ...interface{}) {
if entry.Logger.level() >= DebugLevel {
entry.Debug(entry.sprintlnn(args...))
func (entry *Entry) Logln(level Level, args ...interface{}) {
if entry.Logger.IsLevelEnabled(level) {
entry.Log(level, entry.sprintlnn(args...))
}
}
func (entry *Entry) Infoln(args ...interface{}) {
if entry.Logger.level() >= InfoLevel {
entry.Info(entry.sprintlnn(args...))
func (entry *Entry) Traceln(args ...interface{}) {
entry.Logln(TraceLevel, args...)
}
func (entry *Entry) Debugln(args ...interface{}) {
entry.Logln(DebugLevel, args...)
}
func (entry *Entry) Infoln(args ...interface{}) {
entry.Logln(InfoLevel, args...)
}
func (entry *Entry) Println(args ...interface{}) {
@ -262,9 +363,7 @@ func (entry *Entry) Println(args ...interface{}) {
}
func (entry *Entry) Warnln(args ...interface{}) {
if entry.Logger.level() >= WarnLevel {
entry.Warn(entry.sprintlnn(args...))
}
entry.Logln(WarnLevel, args...)
}
func (entry *Entry) Warningln(args ...interface{}) {
@ -272,22 +371,16 @@ func (entry *Entry) Warningln(args ...interface{}) {
}
func (entry *Entry) Errorln(args ...interface{}) {
if entry.Logger.level() >= ErrorLevel {
entry.Error(entry.sprintlnn(args...))
}
entry.Logln(ErrorLevel, args...)
}
func (entry *Entry) Fatalln(args ...interface{}) {
if entry.Logger.level() >= FatalLevel {
entry.Fatal(entry.sprintlnn(args...))
}
Exit(1)
entry.Logln(FatalLevel, args...)
entry.Logger.Exit(1)
}
func (entry *Entry) Panicln(args ...interface{}) {
if entry.Logger.level() >= PanicLevel {
entry.Panic(entry.sprintlnn(args...))
}
entry.Logln(PanicLevel, args...)
}
// Sprintlnn => Sprint no newline. This is to get the behavior of how

View File

@ -21,30 +21,33 @@ func SetOutput(out io.Writer) {
// SetFormatter sets the standard logger formatter.
func SetFormatter(formatter Formatter) {
std.mu.Lock()
defer std.mu.Unlock()
std.Formatter = formatter
std.SetFormatter(formatter)
}
// SetReportCaller sets whether the standard logger will include the calling
// method as a field.
func SetReportCaller(include bool) {
std.SetReportCaller(include)
}
// SetLevel sets the standard logger level.
func SetLevel(level Level) {
std.mu.Lock()
defer std.mu.Unlock()
std.SetLevel(level)
}
// GetLevel returns the standard logger level.
func GetLevel() Level {
std.mu.Lock()
defer std.mu.Unlock()
return std.level()
return std.GetLevel()
}
// IsLevelEnabled checks if the log level of the standard logger is greater than the level param
func IsLevelEnabled(level Level) bool {
return std.IsLevelEnabled(level)
}
// AddHook adds a hook to the standard logger hooks.
func AddHook(hook Hook) {
std.mu.Lock()
defer std.mu.Unlock()
std.Hooks.Add(hook)
std.AddHook(hook)
}
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
@ -80,6 +83,11 @@ func WithTime(t time.Time) *Entry {
return std.WithTime(t)
}
// Trace logs a message at level Trace on the standard logger.
func Trace(args ...interface{}) {
std.Trace(args...)
}
// Debug logs a message at level Debug on the standard logger.
func Debug(args ...interface{}) {
std.Debug(args...)
@ -120,6 +128,11 @@ func Fatal(args ...interface{}) {
std.Fatal(args...)
}
// Tracef logs a message at level Trace on the standard logger.
func Tracef(format string, args ...interface{}) {
std.Tracef(format, args...)
}
// Debugf logs a message at level Debug on the standard logger.
func Debugf(format string, args ...interface{}) {
std.Debugf(format, args...)
@ -160,6 +173,11 @@ func Fatalf(format string, args ...interface{}) {
std.Fatalf(format, args...)
}
// Traceln logs a message at level Trace on the standard logger.
func Traceln(args ...interface{}) {
std.Traceln(args...)
}
// Debugln logs a message at level Debug on the standard logger.
func Debugln(args ...interface{}) {
std.Debugln(args...)

View File

@ -2,7 +2,16 @@ package logrus
import "time"
const defaultTimestampFormat = time.RFC3339
// Default key names for the default fields
const (
defaultTimestampFormat = time.RFC3339
FieldKeyMsg = "msg"
FieldKeyLevel = "level"
FieldKeyTime = "time"
FieldKeyLogrusError = "logrus_error"
FieldKeyFunc = "func"
FieldKeyFile = "file"
)
// The Formatter interface is used to implement a custom Formatter. It takes an
// `Entry`. It exposes all the fields, including the default ones:
@ -18,7 +27,7 @@ type Formatter interface {
Format(*Entry) ([]byte, error)
}
// This is to not silently overwrite `time`, `msg` and `level` fields when
// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when
// dumping it. If this code wasn't there doing:
//
// logrus.WithField("level", 1).Info("hello")
@ -30,7 +39,7 @@ type Formatter interface {
//
// It's not exported because it's still using Data in an opinionated way. It's to
// avoid code duplication between the two default formatters.
func prefixFieldClashes(data Fields, fieldMap FieldMap) {
func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) {
timeKey := fieldMap.resolve(FieldKeyTime)
if t, ok := data[timeKey]; ok {
data["fields."+timeKey] = t
@ -48,4 +57,22 @@ func prefixFieldClashes(data Fields, fieldMap FieldMap) {
data["fields."+levelKey] = l
delete(data, levelKey)
}
logrusErrKey := fieldMap.resolve(FieldKeyLogrusError)
if l, ok := data[logrusErrKey]; ok {
data["fields."+logrusErrKey] = l
delete(data, logrusErrKey)
}
// If reportCaller is not set, 'func' will not conflict.
if reportCaller {
funcKey := fieldMap.resolve(FieldKeyFunc)
if l, ok := data[funcKey]; ok {
data["fields."+funcKey] = l
}
fileKey := fieldMap.resolve(FieldKeyFile)
if l, ok := data[fileKey]; ok {
data["fields."+fileKey] = l
}
}
}

View File

@ -1,6 +1,7 @@
package logrus
import (
"bytes"
"encoding/json"
"fmt"
)
@ -10,13 +11,6 @@ type fieldKey string
// FieldMap allows customization of the key names for default fields.
type FieldMap map[fieldKey]string
// Default key names for the default fields
const (
FieldKeyMsg = "msg"
FieldKeyLevel = "level"
FieldKeyTime = "time"
)
func (f FieldMap) resolve(key fieldKey) string {
if k, ok := f[key]; ok {
return k
@ -43,14 +37,18 @@ type JSONFormatter struct {
// FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level",
// FieldKeyMsg: "@message",
// FieldKeyFunc: "@caller",
// },
// }
FieldMap FieldMap
// PrettyPrint will indent all json logs
PrettyPrint bool
}
// Format renders a single log entry
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data := make(Fields, len(entry.Data)+3)
data := make(Fields, len(entry.Data)+4)
for k, v := range entry.Data {
switch v := v.(type) {
case error:
@ -68,22 +66,40 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data = newData
}
prefixFieldClashes(data, f.FieldMap)
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = defaultTimestampFormat
}
if entry.err != "" {
data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
}
if !f.DisableTimestamp {
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
}
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
if entry.HasCaller() {
data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function
data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
}
serialized, err := json.Marshal(data)
if err != nil {
var b *bytes.Buffer
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
encoder := json.NewEncoder(b)
if f.PrettyPrint {
encoder.SetIndent("", " ")
}
if err := encoder.Encode(data); err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
return append(serialized, '\n'), nil
return b.Bytes(), nil
}

View File

@ -11,7 +11,7 @@ import (
type Logger struct {
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
// file, or leave it default which is `os.Stderr`. You can also set this to
// something more adventorous, such as logging to Kafka.
// something more adventurous, such as logging to Kafka.
Out io.Writer
// Hooks for the logger instance. These allow firing events based on logging
// levels and log entries. For example, to send errors to an error tracking
@ -24,6 +24,10 @@ type Logger struct {
// own that implements the `Formatter` interface, see the `README` or included
// formatters for examples.
Formatter Formatter
// Flag for whether to log caller info (off by default)
ReportCaller bool
// The logging level the logger should log at. This is typically (and defaults
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
// logged.
@ -32,8 +36,12 @@ type Logger struct {
mu MutexWrap
// Reusable empty entry
entryPool sync.Pool
// Function to exit the application, defaults to `os.Exit()`
ExitFunc exitFunc
}
type exitFunc func(int)
type MutexWrap struct {
lock sync.Mutex
disabled bool
@ -73,6 +81,8 @@ func New() *Logger {
Formatter: new(TextFormatter),
Hooks: make(LevelHooks),
Level: InfoLevel,
ExitFunc: os.Exit,
ReportCaller: false,
}
}
@ -85,6 +95,7 @@ func (logger *Logger) newEntry() *Entry {
}
func (logger *Logger) releaseEntry(entry *Entry) {
entry.Data = map[string]interface{}{}
logger.entryPool.Put(entry)
}
@ -120,20 +131,24 @@ func (logger *Logger) WithTime(t time.Time) *Entry {
return entry.WithTime(t)
}
func (logger *Logger) Debugf(format string, args ...interface{}) {
if logger.level() >= DebugLevel {
func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
if logger.IsLevelEnabled(level) {
entry := logger.newEntry()
entry.Debugf(format, args...)
entry.Logf(level, format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Infof(format string, args ...interface{}) {
if logger.level() >= InfoLevel {
entry := logger.newEntry()
entry.Infof(format, args...)
logger.releaseEntry(entry)
func (logger *Logger) Tracef(format string, args ...interface{}) {
logger.Logf(TraceLevel, format, args...)
}
func (logger *Logger) Debugf(format string, args ...interface{}) {
logger.Logf(DebugLevel, format, args...)
}
func (logger *Logger) Infof(format string, args ...interface{}) {
logger.Logf(InfoLevel, format, args...)
}
func (logger *Logger) Printf(format string, args ...interface{}) {
@ -143,60 +158,44 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
}
func (logger *Logger) Warnf(format string, args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
}
logger.Logf(WarnLevel, format, args...)
}
func (logger *Logger) Warningf(format string, args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
}
logger.Warnf(format, args...)
}
func (logger *Logger) Errorf(format string, args ...interface{}) {
if logger.level() >= ErrorLevel {
entry := logger.newEntry()
entry.Errorf(format, args...)
logger.releaseEntry(entry)
}
logger.Logf(ErrorLevel, format, args...)
}
func (logger *Logger) Fatalf(format string, args ...interface{}) {
if logger.level() >= FatalLevel {
entry := logger.newEntry()
entry.Fatalf(format, args...)
logger.releaseEntry(entry)
}
Exit(1)
logger.Logf(FatalLevel, format, args...)
logger.Exit(1)
}
func (logger *Logger) Panicf(format string, args ...interface{}) {
if logger.level() >= PanicLevel {
logger.Logf(PanicLevel, format, args...)
}
func (logger *Logger) Log(level Level, args ...interface{}) {
if logger.IsLevelEnabled(level) {
entry := logger.newEntry()
entry.Panicf(format, args...)
entry.Log(level, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Trace(args ...interface{}) {
logger.Log(TraceLevel, args...)
}
func (logger *Logger) Debug(args ...interface{}) {
if logger.level() >= DebugLevel {
entry := logger.newEntry()
entry.Debug(args...)
logger.releaseEntry(entry)
}
logger.Log(DebugLevel, args...)
}
func (logger *Logger) Info(args ...interface{}) {
if logger.level() >= InfoLevel {
entry := logger.newEntry()
entry.Info(args...)
logger.releaseEntry(entry)
}
logger.Log(InfoLevel, args...)
}
func (logger *Logger) Print(args ...interface{}) {
@ -206,60 +205,44 @@ func (logger *Logger) Print(args ...interface{}) {
}
func (logger *Logger) Warn(args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
}
logger.Log(WarnLevel, args...)
}
func (logger *Logger) Warning(args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
}
logger.Warn(args...)
}
func (logger *Logger) Error(args ...interface{}) {
if logger.level() >= ErrorLevel {
entry := logger.newEntry()
entry.Error(args...)
logger.releaseEntry(entry)
}
logger.Log(ErrorLevel, args...)
}
func (logger *Logger) Fatal(args ...interface{}) {
if logger.level() >= FatalLevel {
entry := logger.newEntry()
entry.Fatal(args...)
logger.releaseEntry(entry)
}
Exit(1)
logger.Log(FatalLevel, args...)
logger.Exit(1)
}
func (logger *Logger) Panic(args ...interface{}) {
if logger.level() >= PanicLevel {
logger.Log(PanicLevel, args...)
}
func (logger *Logger) Logln(level Level, args ...interface{}) {
if logger.IsLevelEnabled(level) {
entry := logger.newEntry()
entry.Panic(args...)
entry.Logln(level, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Traceln(args ...interface{}) {
logger.Logln(TraceLevel, args...)
}
func (logger *Logger) Debugln(args ...interface{}) {
if logger.level() >= DebugLevel {
entry := logger.newEntry()
entry.Debugln(args...)
logger.releaseEntry(entry)
}
logger.Logln(DebugLevel, args...)
}
func (logger *Logger) Infoln(args ...interface{}) {
if logger.level() >= InfoLevel {
entry := logger.newEntry()
entry.Infoln(args...)
logger.releaseEntry(entry)
}
logger.Logln(InfoLevel, args...)
}
func (logger *Logger) Println(args ...interface{}) {
@ -269,44 +252,32 @@ func (logger *Logger) Println(args ...interface{}) {
}
func (logger *Logger) Warnln(args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
}
logger.Logln(WarnLevel, args...)
}
func (logger *Logger) Warningln(args ...interface{}) {
if logger.level() >= WarnLevel {
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
}
logger.Warn(args...)
}
func (logger *Logger) Errorln(args ...interface{}) {
if logger.level() >= ErrorLevel {
entry := logger.newEntry()
entry.Errorln(args...)
logger.releaseEntry(entry)
}
logger.Logln(ErrorLevel, args...)
}
func (logger *Logger) Fatalln(args ...interface{}) {
if logger.level() >= FatalLevel {
entry := logger.newEntry()
entry.Fatalln(args...)
logger.releaseEntry(entry)
}
Exit(1)
logger.Logln(FatalLevel, args...)
logger.Exit(1)
}
func (logger *Logger) Panicln(args ...interface{}) {
if logger.level() >= PanicLevel {
entry := logger.newEntry()
entry.Panicln(args...)
logger.releaseEntry(entry)
logger.Logln(PanicLevel, args...)
}
func (logger *Logger) Exit(code int) {
runHandlers()
if logger.ExitFunc == nil {
logger.ExitFunc = os.Exit
}
logger.ExitFunc(code)
}
//When file is opened with appending mode, it's safe to
@ -320,18 +291,53 @@ func (logger *Logger) level() Level {
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
}
// SetLevel sets the logger level.
func (logger *Logger) SetLevel(level Level) {
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
}
func (logger *Logger) SetOutput(out io.Writer) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Out = out
// GetLevel returns the logger level.
func (logger *Logger) GetLevel() Level {
return logger.level()
}
// AddHook adds a hook to the logger hooks.
func (logger *Logger) AddHook(hook Hook) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Hooks.Add(hook)
}
// IsLevelEnabled checks if the log level of the logger is greater than the level param
func (logger *Logger) IsLevelEnabled(level Level) bool {
return logger.level() >= level
}
// SetFormatter sets the logger formatter.
func (logger *Logger) SetFormatter(formatter Formatter) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Formatter = formatter
}
// SetOutput sets the logger output.
func (logger *Logger) SetOutput(output io.Writer) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Out = output
}
func (logger *Logger) SetReportCaller(reportCaller bool) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.ReportCaller = reportCaller
}
// ReplaceHooks replaces the logger hooks and returns the old ones
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
logger.mu.Lock()
oldHooks := logger.Hooks
logger.Hooks = hooks
logger.mu.Unlock()
return oldHooks
}

View File

@ -14,23 +14,12 @@ type Level uint32
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
func (level Level) String() string {
switch level {
case DebugLevel:
return "debug"
case InfoLevel:
return "info"
case WarnLevel:
return "warning"
case ErrorLevel:
return "error"
case FatalLevel:
return "fatal"
case PanicLevel:
return "panic"
}
if b, err := level.MarshalText(); err == nil {
return string(b)
} else {
return "unknown"
}
}
// ParseLevel takes a string level and returns the Logrus log level constant.
func ParseLevel(lvl string) (Level, error) {
@ -47,12 +36,47 @@ func ParseLevel(lvl string) (Level, error) {
return InfoLevel, nil
case "debug":
return DebugLevel, nil
case "trace":
return TraceLevel, nil
}
var l Level
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (level *Level) UnmarshalText(text []byte) error {
l, err := ParseLevel(string(text))
if err != nil {
return err
}
*level = Level(l)
return nil
}
func (level Level) MarshalText() ([]byte, error) {
switch level {
case TraceLevel:
return []byte("trace"), nil
case DebugLevel:
return []byte("debug"), nil
case InfoLevel:
return []byte("info"), nil
case WarnLevel:
return []byte("warning"), nil
case ErrorLevel:
return []byte("error"), nil
case FatalLevel:
return []byte("fatal"), nil
case PanicLevel:
return []byte("panic"), nil
}
return nil, fmt.Errorf("not a valid lorus level %q", level)
}
// A constant exposing all logging levels
var AllLevels = []Level{
PanicLevel,
@ -61,6 +85,7 @@ var AllLevels = []Level{
WarnLevel,
InfoLevel,
DebugLevel,
TraceLevel,
}
// These are the different logging levels. You can set the logging level to log
@ -69,7 +94,7 @@ const (
// PanicLevel level, highest level of severity. Logs and then calls panic with the
// message passed to Debug, Info, ...
PanicLevel Level = iota
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
// FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the
// logging level is set to Panic.
FatalLevel
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
@ -82,6 +107,8 @@ const (
InfoLevel
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
DebugLevel
// TraceLevel level. Designates finer-grained informational events than the Debug.
TraceLevel
)
// Won't compile if StdLogger can't be realized by a log.Logger
@ -140,4 +167,20 @@ type FieldLogger interface {
Errorln(args ...interface{})
Fatalln(args ...interface{})
Panicln(args ...interface{})
// IsDebugEnabled() bool
// IsInfoEnabled() bool
// IsWarnEnabled() bool
// IsErrorEnabled() bool
// IsFatalEnabled() bool
// IsPanicEnabled() bool
}
// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is
// here for consistancy. Do not use. Use Logger or Entry instead.
type Ext1FieldLogger interface {
FieldLogger
Tracef(format string, args ...interface{})
Trace(args ...interface{})
Traceln(args ...interface{})
}

View File

@ -1,10 +0,0 @@
// +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine,!gopherjs
package logrus
import "golang.org/x/sys/unix"
const ioctlReadTermios = unix.TIOCGETA
type Termios unix.Termios

View File

@ -0,0 +1,9 @@
// +build !appengine,!js,!windows,aix
package logrus
import "io"
func checkIfTerminal(w io.Writer) bool {
return false
}

Some files were not shown because too many files have changed in this diff Show More