Merge pull request #1234 from dmcgowan/update-logrus

update to github.com/sirupsen/logrus v1.0.0 [carry #1136]
This commit is contained in:
Stephen Day 2017-07-21 16:26:24 -07:00 committed by GitHub
commit 4118a256e9
82 changed files with 2194 additions and 598 deletions

View File

@ -12,10 +12,10 @@ import (
"testing" "testing"
"time" "time"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/testutil" "github.com/containerd/containerd/testutil"
"github.com/sirupsen/logrus"
) )
var ( var (

View File

@ -13,11 +13,11 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/linux/shim" "github.com/containerd/containerd/linux/shim"
shimapi "github.com/containerd/containerd/linux/shim/v1" shimapi "github.com/containerd/containerd/linux/shim/v1"
"github.com/containerd/containerd/reaper" "github.com/containerd/containerd/reaper"
"github.com/containerd/containerd/version" "github.com/containerd/containerd/version"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )

View File

@ -11,12 +11,12 @@ import (
gocontext "golang.org/x/net/context" gocontext "golang.org/x/net/context"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/containerd/containerd/server" "github.com/containerd/containerd/server"
"github.com/containerd/containerd/sys" "github.com/containerd/containerd/sys"
"github.com/containerd/containerd/version" "github.com/containerd/containerd/version"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )

View File

@ -3,9 +3,9 @@ package main
import ( import (
"os" "os"
"github.com/Sirupsen/logrus"
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )

View File

@ -3,9 +3,9 @@ package main
import ( import (
"errors" "errors"
"github.com/Sirupsen/logrus"
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )

View File

@ -4,10 +4,10 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/server" "github.com/containerd/containerd/server"
"github.com/containerd/containerd/version" "github.com/containerd/containerd/version"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )

View File

@ -4,12 +4,12 @@ import (
gocontext "context" gocontext "context"
"syscall" "syscall"
"github.com/Sirupsen/logrus"
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd" "github.com/containerd/containerd"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )

View File

@ -9,12 +9,12 @@ import (
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"github.com/Sirupsen/logrus"
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd" "github.com/containerd/containerd"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/image-spec/specs-go/v1"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )

View File

@ -4,7 +4,6 @@ import (
gocontext "context" gocontext "context"
"time" "time"
"github.com/Sirupsen/logrus"
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
@ -12,6 +11,7 @@ import (
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )

View File

@ -17,7 +17,6 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/grpclog" "google.golang.org/grpc/grpclog"
"github.com/Sirupsen/logrus"
"github.com/containerd/console" "github.com/containerd/console"
shim "github.com/containerd/containerd/linux/shim/v1" shim "github.com/containerd/containerd/linux/shim/v1"
"github.com/containerd/containerd/typeurl" "github.com/containerd/containerd/typeurl"
@ -25,6 +24,7 @@ import (
google_protobuf "github.com/golang/protobuf/ptypes/empty" google_protobuf "github.com/golang/protobuf/ptypes/empty"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )

View File

@ -7,12 +7,12 @@ import (
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/progress" "github.com/containerd/containerd/progress"
"github.com/containerd/containerd/rootfs" "github.com/containerd/containerd/rootfs"
"github.com/containerd/containerd/snapshot" "github.com/containerd/containerd/snapshot"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )

View File

@ -16,7 +16,6 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/Sirupsen/logrus"
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd" "github.com/containerd/containerd"
containersapi "github.com/containerd/containerd/api/services/containers/v1" containersapi "github.com/containerd/containerd/api/services/containers/v1"
@ -43,6 +42,7 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
"google.golang.org/grpc" "google.golang.org/grpc"
) )

View File

@ -3,9 +3,9 @@ package events
import ( import (
"context" "context"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/sirupsen/logrus"
) )
var ( var (

View File

@ -4,13 +4,13 @@ import (
"context" "context"
"time" "time"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/api/services/events/v1" "github.com/containerd/containerd/api/services/events/v1"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/typeurl" "github.com/containerd/containerd/typeurl"
goevents "github.com/docker/go-events" goevents "github.com/docker/go-events"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
) )
type sinkEvent struct { type sinkEvent struct {

View File

@ -8,7 +8,7 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// ChangeKind is the type of modification that // ChangeKind is the type of modification that

View File

@ -14,8 +14,8 @@ import (
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"github.com/Sirupsen/logrus"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
shim "github.com/containerd/containerd/linux/shim/v1" shim "github.com/containerd/containerd/linux/shim/v1"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"

View File

@ -4,7 +4,7 @@ import (
"context" "context"
"path" "path"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var ( var (

View File

@ -8,10 +8,10 @@ import (
"strconv" "strconv"
"sync" "sync"
"github.com/Sirupsen/logrus"
"github.com/containerd/cgroups" "github.com/containerd/cgroups"
metrics "github.com/docker/go-metrics" metrics "github.com/docker/go-metrics"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"
) )
var ( var (

View File

@ -7,9 +7,9 @@ import (
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"github.com/Sirupsen/logrus"
"github.com/containerd/cgroups" "github.com/containerd/cgroups"
metrics "github.com/docker/go-metrics" metrics "github.com/docker/go-metrics"
"github.com/sirupsen/logrus"
) )
func NewOOMCollector(ns *metrics.Namespace) (*OOMCollector, error) { func NewOOMCollector(ns *metrics.Namespace) (*OOMCollector, error) {

View File

@ -7,11 +7,11 @@ import (
"path" "path"
"strings" "strings"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
) )
type dockerFetcher struct { type dockerFetcher struct {

View File

@ -13,7 +13,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/containerd/containerd/reference" "github.com/containerd/containerd/reference"
@ -21,6 +20,7 @@ import (
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/net/context/ctxhttp" "golang.org/x/net/context/ctxhttp"
) )

View File

@ -5,12 +5,12 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus"
) )
// MakeRef returns a unique reference for the descriptor. This reference can be // MakeRef returns a unique reference for the descriptor. This reference can be

View File

@ -4,7 +4,6 @@ import (
"io" "io"
"sync" "sync"
"github.com/Sirupsen/logrus"
"github.com/boltdb/bolt" "github.com/boltdb/bolt"
api "github.com/containerd/containerd/api/services/content/v1" api "github.com/containerd/containerd/api/services/content/v1"
eventsapi "github.com/containerd/containerd/api/services/events/v1" eventsapi "github.com/containerd/containerd/api/services/events/v1"
@ -17,6 +16,7 @@ import (
"github.com/golang/protobuf/ptypes/empty" "github.com/golang/protobuf/ptypes/empty"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/net/context" "golang.org/x/net/context"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"

View File

@ -4,11 +4,11 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/Sirupsen/logrus"
api "github.com/containerd/containerd/api/services/events/v1" api "github.com/containerd/containerd/api/services/events/v1"
"github.com/containerd/containerd/events" "github.com/containerd/containerd/events"
"github.com/containerd/containerd/plugin" "github.com/containerd/containerd/plugin"
"github.com/golang/protobuf/ptypes/empty" "github.com/golang/protobuf/ptypes/empty"
"github.com/sirupsen/logrus"
"golang.org/x/net/context" "golang.org/x/net/context"
"google.golang.org/grpc" "google.golang.org/grpc"
) )

View File

@ -8,7 +8,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/Sirupsen/logrus"
"github.com/containerd/btrfs" "github.com/containerd/btrfs"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/containerd/containerd/mount" "github.com/containerd/containerd/mount"
@ -16,6 +15,7 @@ import (
"github.com/containerd/containerd/snapshot" "github.com/containerd/containerd/snapshot"
"github.com/containerd/containerd/snapshot/storage" "github.com/containerd/containerd/snapshot/storage"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
) )
func init() { func init() {

View File

@ -3,7 +3,7 @@ github.com/containerd/go-runc 2774a2ea124a5c2d0aba13b5c2dd8a5a9a48775d
github.com/containerd/console 7fed77e673ca4abcd0cbd6d4d0e0e22137cbd778 github.com/containerd/console 7fed77e673ca4abcd0cbd6d4d0e0e22137cbd778
github.com/containerd/cgroups 4fd64a776f25b5540cddcb72eea6e35e58baca6e github.com/containerd/cgroups 4fd64a776f25b5540cddcb72eea6e35e58baca6e
github.com/docker/go-metrics 8fd5772bf1584597834c6f7961a530f06cbfbb87 github.com/docker/go-metrics 8fd5772bf1584597834c6f7961a530f06cbfbb87
github.com/docker/go-events aa2e3b613fbbfdddbe055a7b9e3ce271cfd83eca github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/godbus/dbus c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f github.com/godbus/dbus c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f
github.com/prometheus/client_golang v0.8.0 github.com/prometheus/client_golang v0.8.0
github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6 github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
@ -16,7 +16,7 @@ github.com/gogo/protobuf d2e1ade2d719b78fe5b061b4c18a9f7111b5bdc8
github.com/golang/protobuf 5a0f697c9ed9d68fef0116532c6e05cfeae00e55 github.com/golang/protobuf 5a0f697c9ed9d68fef0116532c6e05cfeae00e55
github.com/opencontainers/runtime-spec 96de01bbb42c7af89bff100e10a9f0fb62e75bfb github.com/opencontainers/runtime-spec 96de01bbb42c7af89bff100e10a9f0fb62e75bfb
github.com/opencontainers/runc 429a5387123625040bacfbb60d96b1cbd02293ab github.com/opencontainers/runc 429a5387123625040bacfbb60d96b1cbd02293ab
github.com/Sirupsen/logrus v0.11.0 github.com/sirupsen/logrus v1.0.0
github.com/containerd/btrfs e9c546f46bccffefe71a6bc137e4c21b5503cc18 github.com/containerd/btrfs e9c546f46bccffefe71a6bc137e4c21b5503cc18
github.com/stretchr/testify v1.1.4 github.com/stretchr/testify v1.1.4
github.com/davecgh/go-spew v1.1.0 github.com/davecgh/go-spew v1.1.0
@ -35,8 +35,9 @@ github.com/BurntSushi/toml v0.2.0-21-g9906417
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0 github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
github.com/Microsoft/go-winio v0.4.3 github.com/Microsoft/go-winio v0.4.3
github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd
github.com/Microsoft/hcsshim v0.5.15 # Based on v0.6.0, pending https://github.com/Microsoft/hcsshim/pull/136
github.com/Azure/go-ansiterm fa152c58bc15761d0200cb75fe958b89a9d4888e github.com/Microsoft/hcsshim 007f139973e2d02396f37b7f0a87bedec7716dce https://github.com/dmcgowan/hcsshim.git
github.com/Azure/go-ansiterm 19f72df4d05d31cbe1c56bfc8045c96babff6c7e
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4 golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
github.com/dmcgowan/go-tar 2e2c51242e8993c50445dab7c03c8e7febddd0cf github.com/dmcgowan/go-tar 2e2c51242e8993c50445dab7c03c8e7febddd0cf

View File

@ -5,7 +5,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var logger *logrus.Logger var logger *logrus.Logger

View File

@ -9,7 +9,7 @@ import (
"strconv" "strconv"
"github.com/Azure/go-ansiterm" "github.com/Azure/go-ansiterm"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var logger *logrus.Logger var logger *logrus.Logger

View File

@ -1,6 +1,6 @@
package hcsshim package hcsshim
import "github.com/Sirupsen/logrus" import "github.com/sirupsen/logrus"
// ActivateLayer will find the layer with the given id and mount it's filesystem. // ActivateLayer will find the layer with the given id and mount it's filesystem.
// For a read/write layer, the mounted filesystem will appear as a volume on the // For a read/write layer, the mounted filesystem will appear as a volume on the

View File

@ -4,12 +4,11 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"runtime"
"sync" "sync"
"syscall" "syscall"
"time" "time"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var ( var (
@ -17,9 +16,10 @@ var (
) )
const ( const (
pendingUpdatesQuery = `{ "PropertyTypes" : ["PendingUpdates"]}` pendingUpdatesQuery = `{ "PropertyTypes" : ["PendingUpdates"]}`
statisticsQuery = `{ "PropertyTypes" : ["Statistics"]}` statisticsQuery = `{ "PropertyTypes" : ["Statistics"]}`
processListQuery = `{ "PropertyTypes" : ["ProcessList"]}` processListQuery = `{ "PropertyTypes" : ["ProcessList"]}`
mappedVirtualDiskQuery = `{ "PropertyTypes" : ["MappedVirtualDisk"]}`
) )
type container struct { type container struct {
@ -31,21 +31,21 @@ type container struct {
// ContainerProperties holds the properties for a container and the processes running in that container // ContainerProperties holds the properties for a container and the processes running in that container
type ContainerProperties struct { type ContainerProperties struct {
ID string `json:"Id"` ID string `json:"Id"`
Name string Name string
SystemType string SystemType string
Owner string Owner string
SiloGUID string `json:"SiloGuid,omitempty"` SiloGUID string `json:"SiloGuid,omitempty"`
IsDummy bool `json:",omitempty"` RuntimeID string `json:"RuntimeId,omitempty"`
RuntimeID string `json:"RuntimeId,omitempty"` IsRuntimeTemplate bool `json:",omitempty"`
IsRuntimeTemplate bool `json:",omitempty"` RuntimeImagePath string `json:",omitempty"`
RuntimeImagePath string `json:",omitempty"` Stopped bool `json:",omitempty"`
Stopped bool `json:",omitempty"` ExitType string `json:",omitempty"`
ExitType string `json:",omitempty"` AreUpdatesPending bool `json:",omitempty"`
AreUpdatesPending bool `json:",omitempty"` ObRoot string `json:",omitempty"`
ObRoot string `json:",omitempty"` Statistics Statistics `json:",omitempty"`
Statistics Statistics `json:",omitempty"` ProcessList []ProcessListItem `json:",omitempty"`
ProcessList []ProcessListItem `json:",omitempty"` MappedVirtualDiskControllers map[int]MappedVirtualDiskController `json:",omitempty"`
} }
// MemoryStats holds the memory statistics for a container // MemoryStats holds the memory statistics for a container
@ -105,6 +105,11 @@ type ProcessListItem struct {
UserTime100ns uint64 `json:",omitempty"` UserTime100ns uint64 `json:",omitempty"`
} }
// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
type MappedVirtualDiskController struct {
MappedVirtualDisks map[int]MappedVirtualDisk `json:",omitempty"`
}
// Type of Request Support in ModifySystem // Type of Request Support in ModifySystem
type RequestType string type RequestType string
@ -122,7 +127,7 @@ const (
// Supported resource types are Network and Request Types are Add/Remove // Supported resource types are Network and Request Types are Add/Remove
type ResourceModificationRequestResponse struct { type ResourceModificationRequestResponse struct {
Resource ResourceType `json:"ResourceType"` Resource ResourceType `json:"ResourceType"`
Data string `json:"Settings"` Data interface{} `json:"Settings"`
Request RequestType `json:"RequestType,omitempty"` Request RequestType `json:"RequestType,omitempty"`
} }
@ -206,7 +211,6 @@ func createContainerWithJSON(id string, c *ContainerConfig, additionalJSON strin
} }
logrus.Debugf(title+" succeeded id=%s handle=%d", id, container.handle) logrus.Debugf(title+" succeeded id=%s handle=%d", id, container.handle)
runtime.SetFinalizer(container, closeContainer)
return container, nil return container, nil
} }
@ -264,7 +268,6 @@ func OpenContainer(id string) (Container, error) {
} }
logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle) logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle)
runtime.SetFinalizer(container, closeContainer)
return container, nil return container, nil
} }
@ -491,6 +494,55 @@ func (container *container) ProcessList() ([]ProcessListItem, error) {
return properties.ProcessList, nil return properties.ProcessList, nil
} }
// MappedVirtualDisks returns a map of the controllers and the disks mapped
// to a container.
//
// Example of JSON returned by the query.
//{
// "Id":"1126e8d7d279c707a666972a15976371d365eaf622c02cea2c442b84f6f550a3_svm",
// "SystemType":"Container",
// "RuntimeOsType":"Linux",
// "RuntimeId":"00000000-0000-0000-0000-000000000000",
// "State":"Running",
// "MappedVirtualDiskControllers":{
// "0":{
// "MappedVirtualDisks":{
// "2":{
// "HostPath":"C:\\lcow\\lcow\\scratch\\1126e8d7d279c707a666972a15976371d365eaf622c02cea2c442b84f6f550a3.vhdx",
// "ContainerPath":"/mnt/gcs/LinuxServiceVM/scratch",
// "Lun":2,
// "CreateInUtilityVM":true
// },
// "3":{
// "HostPath":"C:\\lcow\\lcow\\1126e8d7d279c707a666972a15976371d365eaf622c02cea2c442b84f6f550a3\\sandbox.vhdx",
// "Lun":3,
// "CreateInUtilityVM":true,
// "AttachOnly":true
// }
// }
// }
// }
//}
func (container *container) MappedVirtualDisks() (map[int]MappedVirtualDiskController, error) {
container.handleLock.RLock()
defer container.handleLock.RUnlock()
operation := "MappedVirtualDiskList"
title := "HCSShim::Container::" + operation
logrus.Debugf(title+" id=%s", container.id)
if container.handle == 0 {
return nil, makeContainerError(container, operation, "", ErrAlreadyClosed)
}
properties, err := container.properties(mappedVirtualDiskQuery)
if err != nil {
return nil, makeContainerError(container, operation, "", err)
}
logrus.Debugf(title+" succeeded id=%s", container.id)
return properties.MappedVirtualDiskControllers, nil
}
// Pause pauses the execution of the container. This feature is not enabled in TP5. // Pause pauses the execution of the container. This feature is not enabled in TP5.
func (container *container) Pause() error { func (container *container) Pause() error {
container.handleLock.RLock() container.handleLock.RLock()
@ -588,8 +640,7 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
return nil, makeContainerError(container, operation, "", err) return nil, makeContainerError(container, operation, "", err)
} }
logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) logrus.Debugf(title+" succeeded id=%s processid=%d", container.id, process.processID)
runtime.SetFinalizer(process, closeProcess)
return process, nil return process, nil
} }
@ -626,7 +677,6 @@ func (container *container) OpenProcess(pid int) (Process, error) {
} }
logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID)
runtime.SetFinalizer(process, closeProcess)
return process, nil return process, nil
} }
@ -652,17 +702,11 @@ func (container *container) Close() error {
} }
container.handle = 0 container.handle = 0
runtime.SetFinalizer(container, nil)
logrus.Debugf(title+" succeeded id=%s", container.id) logrus.Debugf(title+" succeeded id=%s", container.id)
return nil return nil
} }
// closeContainer wraps container.Close for use by a finalizer
func closeContainer(container *container) {
container.Close()
}
func (container *container) registerCallback() error { func (container *container) registerCallback() error {
context := &notifcationWatcherContext{ context := &notifcationWatcherContext{
channels: newChannels(), channels: newChannels(),

View File

@ -1,6 +1,6 @@
package hcsshim package hcsshim
import "github.com/Sirupsen/logrus" import "github.com/sirupsen/logrus"
// CreateLayer creates a new, empty, read-only layer on the filesystem based on // CreateLayer creates a new, empty, read-only layer on the filesystem based on
// the parent layer provided. // the parent layer provided.

View File

@ -1,6 +1,6 @@
package hcsshim package hcsshim
import "github.com/Sirupsen/logrus" import "github.com/sirupsen/logrus"
// CreateSandboxLayer creates and populates new read-write layer for use by a container. // CreateSandboxLayer creates and populates new read-write layer for use by a container.
// This requires both the id of the direct parent layer, as well as the full list // This requires both the id of the direct parent layer, as well as the full list

View File

@ -1,6 +1,6 @@
package hcsshim package hcsshim
import "github.com/Sirupsen/logrus" import "github.com/sirupsen/logrus"
// DeactivateLayer will dismount a layer that was mounted via ActivateLayer. // DeactivateLayer will dismount a layer that was mounted via ActivateLayer.
func DeactivateLayer(info DriverInfo, id string) error { func DeactivateLayer(info DriverInfo, id string) error {

View File

@ -1,6 +1,6 @@
package hcsshim package hcsshim
import "github.com/Sirupsen/logrus" import "github.com/sirupsen/logrus"
// DestroyLayer will remove the on-disk files representing the layer with the given // DestroyLayer will remove the on-disk files representing the layer with the given
// id, including that layer's containing folder, if any. // id, including that layer's containing folder, if any.

View File

@ -1,6 +1,6 @@
package hcsshim package hcsshim
import "github.com/Sirupsen/logrus" import "github.com/sirupsen/logrus"
// ExpandSandboxSize expands the size of a layer to at least size bytes. // ExpandSandboxSize expands the size of a layer to at least size bytes.
func ExpandSandboxSize(info DriverInfo, layerId string, size uint64) error { func ExpandSandboxSize(info DriverInfo, layerId string, size uint64) error {

View File

@ -4,11 +4,10 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"runtime"
"syscall" "syscall"
"github.com/Microsoft/go-winio" "github.com/Microsoft/go-winio"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// ExportLayer will create a folder at exportFolderPath and fill that folder with // ExportLayer will create a folder at exportFolderPath and fill that folder with
@ -143,7 +142,6 @@ func NewLayerReader(info DriverInfo, layerID string, parentLayerPaths []string)
if err != nil { if err != nil {
return nil, makeError(err, "ExportLayerBegin", "") return nil, makeError(err, "ExportLayerBegin", "")
} }
runtime.SetFinalizer(r, func(r *FilterLayerReader) { r.Close() })
return r, err return r, err
} }

View File

@ -3,7 +3,7 @@ package hcsshim
import ( import (
"syscall" "syscall"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// GetLayerMountPath will look for a mounted layer with the given id and return // GetLayerMountPath will look for a mounted layer with the given id and return

View File

@ -1,6 +1,6 @@
package hcsshim package hcsshim
import "github.com/Sirupsen/logrus" import "github.com/sirupsen/logrus"
// GetSharedBaseImages will enumerate the images stored in the common central // GetSharedBaseImages will enumerate the images stored in the common central
// image store and return descriptive info about those images for the purpose // image store and return descriptive info about those images for the purpose

View File

@ -8,7 +8,7 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
//go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go //go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go

183
vendor/github.com/Microsoft/hcsshim/hnsendpoint.go generated vendored Normal file
View File

@ -0,0 +1,183 @@
package hcsshim
import (
"encoding/json"
"fmt"
"net"
"github.com/sirupsen/logrus"
)
// HNSEndpoint represents a network endpoint in HNS
type HNSEndpoint struct {
Id string `json:"ID,omitempty"`
Name string `json:",omitempty"`
VirtualNetwork string `json:",omitempty"`
VirtualNetworkName string `json:",omitempty"`
Policies []json.RawMessage `json:",omitempty"`
MacAddress string `json:",omitempty"`
IPAddress net.IP `json:",omitempty"`
DNSSuffix string `json:",omitempty"`
DNSServerList string `json:",omitempty"`
GatewayAddress string `json:",omitempty"`
EnableInternalDNS bool `json:",omitempty"`
DisableICC bool `json:",omitempty"`
PrefixLength uint8 `json:",omitempty"`
IsRemoteEndpoint bool `json:",omitempty"`
}
// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
endpoint := &HNSEndpoint{}
err := hnsCall(method, "/endpoints/"+path, request, &endpoint)
if err != nil {
return nil, err
}
return endpoint, nil
}
// HNSListEndpointRequest makes a HNS call to query the list of available endpoints
func HNSListEndpointRequest() ([]HNSEndpoint, error) {
var endpoint []HNSEndpoint
err := hnsCall("GET", "/endpoints/", "", &endpoint)
if err != nil {
return nil, err
}
return endpoint, nil
}
// HotAttachEndpoint makes a HCS Call to attach the endpoint to the container
func HotAttachEndpoint(containerID string, endpointID string) error {
return modifyNetworkEndpoint(containerID, endpointID, Add)
}
// HotDetachEndpoint makes a HCS Call to detach the endpoint from the container
func HotDetachEndpoint(containerID string, endpointID string) error {
return modifyNetworkEndpoint(containerID, endpointID, Remove)
}
// ModifyContainer corresponding to the container id, by sending a request
func modifyContainer(id string, request *ResourceModificationRequestResponse) error {
container, err := OpenContainer(id)
if err != nil {
if IsNotExist(err) {
return ErrComputeSystemDoesNotExist
}
return getInnerError(err)
}
defer container.Close()
err = container.Modify(request)
if err != nil {
if IsNotSupported(err) {
return ErrPlatformNotSupported
}
return getInnerError(err)
}
return nil
}
func modifyNetworkEndpoint(containerID string, endpointID string, request RequestType) error {
requestMessage := &ResourceModificationRequestResponse{
Resource: Network,
Request: request,
Data: endpointID,
}
err := modifyContainer(containerID, requestMessage)
if err != nil {
return err
}
return nil
}
// GetHNSEndpointByID
func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
return HNSEndpointRequest("GET", endpointID, "")
}
// GetHNSNetworkName filtered by Name
func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
hnsResponse, err := HNSListEndpointRequest()
if err != nil {
return nil, err
}
for _, hnsEndpoint := range hnsResponse {
if hnsEndpoint.Name == endpointName {
return &hnsEndpoint, nil
}
}
return nil, fmt.Errorf("Endpoint %v not found", endpointName)
}
// Create Endpoint by sending EndpointRequest to HNS. TODO: Create a separate HNS interface to place all these methods
func (endpoint *HNSEndpoint) Create() (*HNSEndpoint, error) {
operation := "Create"
title := "HCSShim::HNSEndpoint::" + operation
logrus.Debugf(title+" id=%s", endpoint.Id)
jsonString, err := json.Marshal(endpoint)
if err != nil {
return nil, err
}
return HNSEndpointRequest("POST", "", string(jsonString))
}
// Delete Endpoint by sending EndpointRequest to HNS
func (endpoint *HNSEndpoint) Delete() (*HNSEndpoint, error) {
operation := "Delete"
title := "HCSShim::HNSEndpoint::" + operation
logrus.Debugf(title+" id=%s", endpoint.Id)
return HNSEndpointRequest("DELETE", endpoint.Id, "")
}
// Delete Endpoint by sending EndpointRequest to HNS
func (endpoint *HNSEndpoint) Update() (*HNSEndpoint, error) {
operation := "Update"
title := "HCSShim::HNSEndpoint::" + operation
logrus.Debugf(title+" id=%s", endpoint.Id)
jsonString, err := json.Marshal(endpoint)
if err != nil {
return nil, err
}
err = hnsCall("POST", "/endpoints/"+endpoint.Id+"/update", string(jsonString), &endpoint)
return endpoint, err
}
// Hot Attach an endpoint to a container
func (endpoint *HNSEndpoint) HotAttach(containerID string) error {
operation := "HotAttach"
title := "HCSShim::HNSEndpoint::" + operation
logrus.Debugf(title+" id=%s, containerId=%s", endpoint.Id, containerID)
return modifyNetworkEndpoint(containerID, endpoint.Id, Add)
}
// Hot Detach an endpoint from a container
func (endpoint *HNSEndpoint) HotDetach(containerID string) error {
operation := "HotDetach"
title := "HCSShim::HNSEndpoint::" + operation
logrus.Debugf(title+" id=%s, containerId=%s", endpoint.Id, containerID)
return modifyNetworkEndpoint(containerID, endpoint.Id, Remove)
}
// Apply Acl Policy on the Endpoint
func (endpoint *HNSEndpoint) ApplyACLPolicy(policy *ACLPolicy) error {
operation := "ApplyACLPolicy"
title := "HCSShim::HNSEndpoint::" + operation
logrus.Debugf(title+" id=%s", endpoint.Id)
jsonString, err := json.Marshal(policy)
if err != nil {
return err
}
endpoint.Policies[0] = jsonString
_, err = endpoint.Update()
return err
}

View File

@ -3,99 +3,10 @@ package hcsshim
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
type NatPolicy struct {
Type string
Protocol string
InternalPort uint16
ExternalPort uint16
}
type QosPolicy struct {
Type string
MaximumOutgoingBandwidthInBytes uint64
}
type VlanPolicy struct {
Type string
VLAN uint
}
type VsidPolicy struct {
Type string
VSID uint
}
type PaPolicy struct {
Type string
PA string
}
// Subnet is assoicated with a network and represents a list
// of subnets available to the network
type Subnet struct {
AddressPrefix string `json:",omitempty"`
GatewayAddress string `json:",omitempty"`
Policies []json.RawMessage `json:",omitempty"`
}
// MacPool is assoicated with a network and represents a list
// of macaddresses available to the network
type MacPool struct {
StartMacAddress string `json:",omitempty"`
EndMacAddress string `json:",omitempty"`
}
// HNSNetwork represents a network in HNS
type HNSNetwork struct {
Id string `json:"ID,omitempty"`
Name string `json:",omitempty"`
Type string `json:",omitempty"`
NetworkAdapterName string `json:",omitempty"`
SourceMac string `json:",omitempty"`
Policies []json.RawMessage `json:",omitempty"`
MacPools []MacPool `json:",omitempty"`
Subnets []Subnet `json:",omitempty"`
DNSSuffix string `json:",omitempty"`
DNSServerList string `json:",omitempty"`
DNSServerCompartment uint32 `json:",omitempty"`
ManagementIP string `json:",omitempty"`
}
// HNSEndpoint represents a network endpoint in HNS
type HNSEndpoint struct {
Id string `json:"ID,omitempty"`
Name string `json:",omitempty"`
VirtualNetwork string `json:",omitempty"`
VirtualNetworkName string `json:",omitempty"`
Policies []json.RawMessage `json:",omitempty"`
MacAddress string `json:",omitempty"`
IPAddress net.IP `json:",omitempty"`
DNSSuffix string `json:",omitempty"`
DNSServerList string `json:",omitempty"`
GatewayAddress string `json:",omitempty"`
EnableInternalDNS bool `json:",omitempty"`
DisableICC bool `json:",omitempty"`
PrefixLength uint8 `json:",omitempty"`
IsRemoteEndpoint bool `json:",omitempty"`
}
type hnsNetworkResponse struct {
Success bool
Error string
Output HNSNetwork
}
type hnsResponse struct {
Success bool
Error string
Output json.RawMessage
}
func hnsCall(method, path, request string, returnResponse interface{}) error { func hnsCall(method, path, request string, returnResponse interface{}) error {
var responseBuffer *uint16 var responseBuffer *uint16
logrus.Debugf("[%s]=>[%s] Request : %s", method, path, request) logrus.Debugf("[%s]=>[%s] Request : %s", method, path, request)
@ -127,145 +38,3 @@ func hnsCall(method, path, request string, returnResponse interface{}) error {
return nil return nil
} }
// HNSNetworkRequest makes a call into HNS to update/query a single network
func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
var network HNSNetwork
err := hnsCall(method, "/networks/"+path, request, &network)
if err != nil {
return nil, err
}
return &network, nil
}
// HNSListNetworkRequest makes a HNS call to query the list of available networks
func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
var network []HNSNetwork
err := hnsCall(method, "/networks/"+path, request, &network)
if err != nil {
return nil, err
}
return network, nil
}
// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
endpoint := &HNSEndpoint{}
err := hnsCall(method, "/endpoints/"+path, request, &endpoint)
if err != nil {
return nil, err
}
return endpoint, nil
}
// HNSListEndpointRequest makes a HNS call to query the list of available endpoints
func HNSListEndpointRequest() ([]HNSEndpoint, error) {
var endpoint []HNSEndpoint
err := hnsCall("GET", "/endpoints/", "", &endpoint)
if err != nil {
return nil, err
}
return endpoint, nil
}
// HotAttachEndpoint makes a HCS Call to attach the endpoint to the container
func HotAttachEndpoint(containerID string, endpointID string) error {
return modifyNetworkEndpoint(containerID, endpointID, Add)
}
// HotDetachEndpoint makes a HCS Call to detach the endpoint from the container
func HotDetachEndpoint(containerID string, endpointID string) error {
return modifyNetworkEndpoint(containerID, endpointID, Remove)
}
// ModifyContainer corresponding to the container id, by sending a request
func modifyContainer(id string, request *ResourceModificationRequestResponse) error {
container, err := OpenContainer(id)
if err != nil {
if IsNotExist(err) {
return ErrComputeSystemDoesNotExist
}
return getInnerError(err)
}
defer container.Close()
err = container.Modify(request)
if err != nil {
if IsNotSupported(err) {
return ErrPlatformNotSupported
}
return getInnerError(err)
}
return nil
}
func modifyNetworkEndpoint(containerID string, endpointID string, request RequestType) error {
requestMessage := &ResourceModificationRequestResponse{
Resource: Network,
Request: request,
Data: endpointID,
}
err := modifyContainer(containerID, requestMessage)
if err != nil {
return err
}
return nil
}
// GetHNSNetworkByID
func GetHNSNetworkByID(networkID string) (*HNSNetwork, error) {
return HNSNetworkRequest("GET", networkID, "")
}
// GetHNSNetworkName filtered by Name
func GetHNSNetworkByName(networkName string) (*HNSNetwork, error) {
hsnnetworks, err := HNSListNetworkRequest("GET", "", "")
if err != nil {
return nil, err
}
for _, hnsnetwork := range hsnnetworks {
if hnsnetwork.Name == networkName {
return &hnsnetwork, nil
}
}
return nil, fmt.Errorf("Network %v not found", networkName)
}
// Create Endpoint by sending EndpointRequest to HNS. TODO: Create a separate HNS interface to place all these methods
func (endpoint *HNSEndpoint) Create() (*HNSEndpoint, error) {
jsonString, err := json.Marshal(endpoint)
if err != nil {
return nil, err
}
return HNSEndpointRequest("POST", "", string(jsonString))
}
// Create Endpoint by sending EndpointRequest to HNS
func (endpoint *HNSEndpoint) Delete() (*HNSEndpoint, error) {
return HNSEndpointRequest("DELETE", endpoint.Id, "")
}
// GetHNSEndpointByID
func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
return HNSEndpointRequest("GET", endpointID, "")
}
// GetHNSNetworkName filtered by Name
func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
hnsResponse, err := HNSListEndpointRequest()
if err != nil {
return nil, err
}
for _, hnsEndpoint := range hnsResponse {
if hnsEndpoint.Name == endpointName {
return &hnsEndpoint, nil
}
}
return nil, fmt.Errorf("Endpoint %v not found", endpointName)
}

142
vendor/github.com/Microsoft/hcsshim/hnsnetwork.go generated vendored Normal file
View File

@ -0,0 +1,142 @@
package hcsshim
import (
"encoding/json"
"fmt"
"net"
"github.com/sirupsen/logrus"
)
// Subnet is assoicated with a network and represents a list
// of subnets available to the network
type Subnet struct {
AddressPrefix string `json:",omitempty"`
GatewayAddress string `json:",omitempty"`
Policies []json.RawMessage `json:",omitempty"`
}
// MacPool is assoicated with a network and represents a list
// of macaddresses available to the network
type MacPool struct {
StartMacAddress string `json:",omitempty"`
EndMacAddress string `json:",omitempty"`
}
// HNSNetwork represents a network in HNS
type HNSNetwork struct {
Id string `json:"ID,omitempty"`
Name string `json:",omitempty"`
Type string `json:",omitempty"`
NetworkAdapterName string `json:",omitempty"`
SourceMac string `json:",omitempty"`
Policies []json.RawMessage `json:",omitempty"`
MacPools []MacPool `json:",omitempty"`
Subnets []Subnet `json:",omitempty"`
DNSSuffix string `json:",omitempty"`
DNSServerList string `json:",omitempty"`
DNSServerCompartment uint32 `json:",omitempty"`
ManagementIP string `json:",omitempty"`
AutomaticDNS bool `json:",omitempty"`
}
type hnsNetworkResponse struct {
Success bool
Error string
Output HNSNetwork
}
type hnsResponse struct {
Success bool
Error string
Output json.RawMessage
}
// HNSNetworkRequest makes a call into HNS to update/query a single network
func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
var network HNSNetwork
err := hnsCall(method, "/networks/"+path, request, &network)
if err != nil {
return nil, err
}
return &network, nil
}
// HNSListNetworkRequest makes a HNS call to query the list of available networks
func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
var network []HNSNetwork
err := hnsCall(method, "/networks/"+path, request, &network)
if err != nil {
return nil, err
}
return network, nil
}
// GetHNSNetworkByID
func GetHNSNetworkByID(networkID string) (*HNSNetwork, error) {
return HNSNetworkRequest("GET", networkID, "")
}
// GetHNSNetworkName filtered by Name
func GetHNSNetworkByName(networkName string) (*HNSNetwork, error) {
hsnnetworks, err := HNSListNetworkRequest("GET", "", "")
if err != nil {
return nil, err
}
for _, hnsnetwork := range hsnnetworks {
if hnsnetwork.Name == networkName {
return &hnsnetwork, nil
}
}
return nil, fmt.Errorf("Network %v not found", networkName)
}
// Create Network by sending NetworkRequest to HNS.
func (network *HNSNetwork) Create() (*HNSNetwork, error) {
operation := "Create"
title := "HCSShim::HNSNetwork::" + operation
logrus.Debugf(title+" id=%s", network.Id)
jsonString, err := json.Marshal(network)
if err != nil {
return nil, err
}
return HNSNetworkRequest("POST", "", string(jsonString))
}
// Delete Network by sending NetworkRequest to HNS
func (network *HNSNetwork) Delete() (*HNSNetwork, error) {
operation := "Delete"
title := "HCSShim::HNSNetwork::" + operation
logrus.Debugf(title+" id=%s", network.Id)
return HNSNetworkRequest("DELETE", network.Id, "")
}
// Creates an endpoint on the Network.
func (network *HNSNetwork) NewEndpoint(ipAddress net.IP, macAddress net.HardwareAddr) *HNSEndpoint {
return &HNSEndpoint{
VirtualNetwork: network.Id,
IPAddress: ipAddress,
MacAddress: string(macAddress),
}
}
func (network *HNSNetwork) CreateEndpoint(endpoint *HNSEndpoint) (*HNSEndpoint, error) {
operation := "CreateEndpoint"
title := "HCSShim::HNSNetwork::" + operation
logrus.Debugf(title+" id=%s, endpointId=%s", network.Id, endpoint.Id)
endpoint.VirtualNetwork = network.Id
return endpoint.Create()
}
func (network *HNSNetwork) CreateRemoteEndpoint(endpoint *HNSEndpoint) (*HNSEndpoint, error) {
operation := "CreateRemoteEndpoint"
title := "HCSShim::HNSNetwork::" + operation
logrus.Debugf(title+" id=%s", network.Id)
endpoint.IsRemoteEndpoint = true
return network.CreateEndpoint(endpoint)
}

95
vendor/github.com/Microsoft/hcsshim/hnspolicy.go generated vendored Normal file
View File

@ -0,0 +1,95 @@
package hcsshim
// Type of Request Support in ModifySystem
type PolicyType string
// RequestType const
const (
Nat PolicyType = "NAT"
ACL PolicyType = "ACL"
PA PolicyType = "PA"
VLAN PolicyType = "VLAN"
VSID PolicyType = "VSID"
VNet PolicyType = "VNET"
L2Driver PolicyType = "L2Driver"
Isolation PolicyType = "Isolation"
QOS PolicyType = "QOS"
OutboundNat PolicyType = "OutBoundNAT"
ExternalLoadBalancer PolicyType = "ELB"
Route PolicyType = "ROUTE"
)
type NatPolicy struct {
Type PolicyType `json:"Type"`
Protocol string
InternalPort uint16
ExternalPort uint16
}
type QosPolicy struct {
Type PolicyType `json:"Type"`
MaximumOutgoingBandwidthInBytes uint64
}
type IsolationPolicy struct {
Type PolicyType `json:"Type"`
VLAN uint
VSID uint
InDefaultIsolation bool
}
type VlanPolicy struct {
Type PolicyType `json:"Type"`
VLAN uint
}
type VsidPolicy struct {
Type PolicyType `json:"Type"`
VSID uint
}
type PaPolicy struct {
Type PolicyType `json:"Type"`
PA string `json:"PA"`
}
type OutboundNatPolicy struct {
Policy
VIP string `json:"VIP,omitempty"`
Exceptions []string `json:"ExceptionList,omitempty"`
}
type ActionType string
type DirectionType string
type RuleType string
const (
Allow ActionType = "Allow"
Block ActionType = "Block"
In DirectionType = "In"
Out DirectionType = "Out"
Host RuleType = "Host"
Switch RuleType = "Switch"
)
type ACLPolicy struct {
Type PolicyType `json:"Type"`
Protocol uint16
InternalPort uint16
Action ActionType
Direction DirectionType
LocalAddress string
RemoteAddress string
LocalPort uint16
RemotePort uint16
RuleType RuleType `json:"RuleType,omitempty"`
Priority uint16
ServiceName string
}
type Policy struct {
Type PolicyType `json:"Type"`
}

187
vendor/github.com/Microsoft/hcsshim/hnspolicylist.go generated vendored Normal file
View File

@ -0,0 +1,187 @@
package hcsshim
import (
"encoding/json"
"github.com/sirupsen/logrus"
)
type RoutePolicy struct {
Policy
DestinationPrefix string `json:"DestinationPrefix,omitempty"`
NextHop string `json:"NextHop,omitempty"`
EncapEnabled bool `json:"NeedEncap,omitempty"`
}
type ELBPolicy struct {
LBPolicy
SourceVIP string `json:"SourceVIP,omitempty"`
VIPs []string `json:"VIPs,omitempty"`
ILB bool `json:"ILB,omitempty"`
}
type LBPolicy struct {
Policy
Protocol uint16 `json:"Protocol,omitempty"`
InternalPort uint16
ExternalPort uint16
}
type PolicyList struct {
Id string `json:"ID,omitempty"`
EndpointReferences []string `json:"References,omitempty"`
Policies []string `json:"Policies,omitempty"`
}
// HNSPolicyListRequest makes a call into HNS to update/query a single network
func HNSPolicyListRequest(method, path, request string) (*PolicyList, error) {
var policy PolicyList
err := hnsCall(method, "/policylists/"+path, request, &policy)
if err != nil {
return nil, err
}
return &policy, nil
}
func HNSListPolicyListRequest() ([]PolicyList, error) {
var plist []PolicyList
err := hnsCall("GET", "/policylists/", "", &plist)
if err != nil {
return nil, err
}
return plist, nil
}
// PolicyListRequest makes a HNS call to modify/query a network endpoint
func PolicyListRequest(method, path, request string) (*PolicyList, error) {
policylist := &PolicyList{}
err := hnsCall(method, "/policylists/"+path, request, &policylist)
if err != nil {
return nil, err
}
return policylist, nil
}
// Create PolicyList by sending PolicyListRequest to HNS.
func (policylist *PolicyList) Create() (*PolicyList, error) {
operation := "Create"
title := "HCSShim::PolicyList::" + operation
logrus.Debugf(title+" id=%s", policylist.Id)
jsonString, err := json.Marshal(policylist)
if err != nil {
return nil, err
}
return PolicyListRequest("POST", "", string(jsonString))
}
// Create PolicyList by sending PolicyListRequest to HNS
func (policylist *PolicyList) Delete() (*PolicyList, error) {
operation := "Delete"
title := "HCSShim::PolicyList::" + operation
logrus.Debugf(title+" id=%s", policylist.Id)
return PolicyListRequest("DELETE", policylist.Id, "")
}
// Add an endpoint to a Policy List
func (policylist *PolicyList) AddEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) {
operation := "AddEndpoint"
title := "HCSShim::PolicyList::" + operation
logrus.Debugf(title+" id=%s, endpointId:%s", policylist.Id, endpoint.Id)
_, err := policylist.Delete()
if err != nil {
return nil, err
}
// Add Endpoint to the Existing List
policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id)
return policylist.Create()
}
// Remove an endpoint from the Policy List
func (policylist *PolicyList) RemoveEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) {
operation := "RemoveEndpoint"
title := "HCSShim::PolicyList::" + operation
logrus.Debugf(title+" id=%s, endpointId:%s", policylist.Id, endpoint.Id)
_, err := policylist.Delete()
if err != nil {
return nil, err
}
elementToRemove := "/endpoints/" + endpoint.Id
var references []string
for _, endpointReference := range policylist.EndpointReferences {
if endpointReference == elementToRemove {
continue
}
references = append(references, endpointReference)
}
policylist.EndpointReferences = references
return policylist.Create()
}
// AddLoadBalancer policy list for the specified endpoints
func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
operation := "AddLoadBalancer"
title := "HCSShim::PolicyList::" + operation
logrus.Debugf(title+" Vip:%s", vip)
policylist := &PolicyList{}
elbPolicy := &ELBPolicy{
VIPs: []string{vip},
ILB: isILB,
}
elbPolicy.Type = ExternalLoadBalancer
elbPolicy.Protocol = protocol
elbPolicy.InternalPort = internalPort
elbPolicy.ExternalPort = externalPort
for _, endpoint := range endpoints {
policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id)
}
jsonString, err := json.Marshal(elbPolicy)
if err != nil {
return nil, err
}
policylist.Policies[0] = string(jsonString)
return policylist.Create()
}
// AddLoadBalancer policy list for the specified endpoints
func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) {
operation := "AddRoute"
title := "HCSShim::PolicyList::" + operation
logrus.Debugf(title+" destinationPrefix:%s", destinationPrefix)
policylist := &PolicyList{}
rPolicy := &RoutePolicy{
DestinationPrefix: destinationPrefix,
NextHop: nextHop,
EncapEnabled: encapEnabled,
}
rPolicy.Type = Route
for _, endpoint := range endpoints {
policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id)
}
jsonString, err := json.Marshal(rPolicy)
if err != nil {
return nil, err
}
policylist.Policies[0] = string(jsonString)
return policylist.Create()
}

View File

@ -5,10 +5,9 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"github.com/Microsoft/go-winio" "github.com/Microsoft/go-winio"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// ImportLayer will take the contents of the folder at importFolderPath and import // ImportLayer will take the contents of the folder at importFolderPath and import
@ -209,6 +208,5 @@ func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string)
if err != nil { if err != nil {
return nil, makeError(err, "ImportLayerStart", "") return nil, makeError(err, "ImportLayerStart", "")
} }
runtime.SetFinalizer(w, func(w *FilterLayerWriter) { w.Close() })
return w, nil return w, nil
} }

View File

@ -1,6 +1,7 @@
package hcsshim package hcsshim
import ( import (
"encoding/json"
"io" "io"
"time" "time"
) )
@ -8,16 +9,19 @@ import (
// ProcessConfig is used as both the input of Container.CreateProcess // ProcessConfig is used as both the input of Container.CreateProcess
// and to convert the parameters to JSON for passing onto the HCS // and to convert the parameters to JSON for passing onto the HCS
type ProcessConfig struct { type ProcessConfig struct {
ApplicationName string ApplicationName string `json:",omitempty"`
CommandLine string CommandLine string `json:",omitempty"`
User string CommandArgs []string `json:",omitempty"` // Used by Linux Containers on Windows
WorkingDirectory string User string `json:",omitempty"`
Environment map[string]string WorkingDirectory string `json:",omitempty"`
EmulateConsole bool Environment map[string]string `json:",omitempty"`
CreateStdInPipe bool EmulateConsole bool `json:",omitempty"`
CreateStdOutPipe bool CreateStdInPipe bool `json:",omitempty"`
CreateStdErrPipe bool CreateStdOutPipe bool `json:",omitempty"`
ConsoleSize [2]uint CreateStdErrPipe bool `json:",omitempty"`
ConsoleSize [2]uint `json:",omitempty"`
CreateInUtilityVm bool `json:",omitempty"` // Used by Linux Containers on Windows
OCISpecification *json.RawMessage `json:",omitempty"` // Used by Linux Containers on Windows
} }
type Layer struct { type Layer struct {
@ -33,40 +37,59 @@ type MappedDir struct {
IOPSMaximum uint64 IOPSMaximum uint64
} }
type MappedPipe struct {
HostPath string
ContainerPipeName string
}
type HvRuntime struct { type HvRuntime struct {
ImagePath string `json:",omitempty"` ImagePath string `json:",omitempty"`
SkipTemplate bool `json:",omitempty"` SkipTemplate bool `json:",omitempty"`
LinuxInitrdFile string `json:",omitempty"` // File under ImagePath on host containing an initrd image for starting a Linux utility VM
LinuxKernelFile string `json:",omitempty"` // File under ImagePath on host containing a kernel for starting a Linux utility VM
LinuxBootParameters string `json:",omitempty"` // Additional boot parameters for starting a Linux Utility VM in initrd mode
}
type MappedVirtualDisk struct {
HostPath string `json:",omitempty"` // Path to VHD on the host
ContainerPath string // Platform-specific mount point path in the container
CreateInUtilityVM bool `json:",omitempty"`
ReadOnly bool `json:",omitempty"`
Cache string `json:",omitempty"` // "" (Unspecified); "Disabled"; "Enabled"; "Private"; "PrivateAllowSharing"
AttachOnly bool `json:",omitempty:`
} }
// ContainerConfig is used as both the input of CreateContainer // ContainerConfig is used as both the input of CreateContainer
// and to convert the parameters to JSON for passing onto the HCS // and to convert the parameters to JSON for passing onto the HCS
type ContainerConfig struct { type ContainerConfig struct {
SystemType string // HCS requires this to be hard-coded to "Container" SystemType string // HCS requires this to be hard-coded to "Container"
Name string // Name of the container. We use the docker ID. Name string // Name of the container. We use the docker ID.
Owner string // The management platform that created this container Owner string `json:",omitempty"` // The management platform that created this container
IsDummy bool // Used for development purposes. VolumePath string `json:",omitempty"` // Windows volume path for scratch space. Used by Windows Server Containers only. Format \\?\\Volume{GUID}
VolumePath string `json:",omitempty"` // Windows volume path for scratch space. Used by Windows Server Containers only. Format \\?\\Volume{GUID} IgnoreFlushesDuringBoot bool `json:",omitempty"` // Optimization hint for container startup in Windows
IgnoreFlushesDuringBoot bool // Optimization hint for container startup in Windows LayerFolderPath string `json:",omitempty"` // Where the layer folders are located. Used by Windows Server Containers only. Format %root%\windowsfilter\containerID
LayerFolderPath string `json:",omitempty"` // Where the layer folders are located. Used by Windows Server Containers only. Format %root%\windowsfilter\containerID Layers []Layer // List of storage layers. Required for Windows Server and Hyper-V Containers. Format ID=GUID;Path=%root%\windowsfilter\layerID
Layers []Layer // List of storage layers. Required for Windows Server and Hyper-V Containers. Format ID=GUID;Path=%root%\windowsfilter\layerID Credentials string `json:",omitempty"` // Credentials information
Credentials string `json:",omitempty"` // Credentials information ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container.
ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container. ProcessorWeight uint64 `json:",omitempty"` // CPU shares (relative weight to other containers with cpu shares). Range is from 1 to 10000. A value of 0 results in default shares.
ProcessorWeight uint64 `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default. ProcessorMaximum int64 `json:",omitempty"` // Specifies the portion of processor cycles that this container can use as a percentage times 100. Range is from 1 to 10000. A value of 0 results in no limit.
ProcessorMaximum int64 `json:",omitempty"` // CPU maximum usage percent 1..100 StorageIOPSMaximum uint64 `json:",omitempty"` // Maximum Storage IOPS
StorageIOPSMaximum uint64 `json:",omitempty"` // Maximum Storage IOPS StorageBandwidthMaximum uint64 `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second
StorageBandwidthMaximum uint64 `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second StorageSandboxSize uint64 `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller
StorageSandboxSize uint64 `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes
MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes HostName string `json:",omitempty"` // Hostname
HostName string // Hostname MappedDirectories []MappedDir `json:",omitempty"` // List of mapped directories (volumes/mounts)
MappedDirectories []MappedDir // List of mapped directories (volumes/mounts) MappedPipes []MappedPipe `json:",omitempty"` // List of mapped Windows named pipes
SandboxPath string `json:",omitempty"` // Location of unmounted sandbox. Used by Hyper-V containers only. Format %root%\windowsfilter HvPartition bool // True if it a Hyper-V Container
HvPartition bool // True if it a Hyper-V Container NetworkSharedContainerName string `json:",omitempty"` // Name (ID) of the container that we will share the network stack with.
EndpointList []string // List of networking endpoints to be attached to container EndpointList []string `json:",omitempty"` // List of networking endpoints to be attached to container
NetworkSharedContainerName string `json:",omitempty"` // Name (ID) of the container that we will share the network stack with. HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM
HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM Servicing bool `json:",omitempty"` // True if this container is for servicing
Servicing bool // True if this container is for servicing AllowUnqualifiedDNSQuery bool `json:",omitempty"` // True to allow unqualified DNS name resolution
AllowUnqualifiedDNSQuery bool // True to allow unqualified DNS name resolution DNSSearchList string `json:",omitempty"` // Comma seperated list of DNS suffixes to use for name resolution
DNSSearchList string `json:",omitempty"` // Comma seperated list of DNS suffixes to use for name resolution ContainerType string `json:",omitempty"` // "Linux" for Linux containers on Windows. Omitted otherwise.
TerminateOnLastHandleClosed bool `json:",omitempty"` // Should HCS terminate the container once all handles have been closed
MappedVirtualDisks []MappedVirtualDisk `json:",omitempty"` // Array of virtual disks to mount at start
} }
type ComputeSystemQuery struct { type ComputeSystemQuery struct {
@ -109,6 +132,9 @@ type Container interface {
// ProcessList returns details for the processes in a container. // ProcessList returns details for the processes in a container.
ProcessList() ([]ProcessListItem, error) ProcessList() ([]ProcessListItem, error)
// MappedVirtualDisks returns virtual disks mapped to a utility VM, indexed by controller
MappedVirtualDisks() (map[int]MappedVirtualDiskController, error)
// CreateProcess launches a new process within the container. // CreateProcess launches a new process within the container.
CreateProcess(c *ProcessConfig) (Process, error) CreateProcess(c *ProcessConfig) (Process, error)

View File

@ -1,6 +1,6 @@
package hcsshim package hcsshim
import "github.com/Sirupsen/logrus" import "github.com/sirupsen/logrus"
// LayerExists will return true if a layer with the given id exists and is known // LayerExists will return true if a layer with the given id exists and is known
// to the system. // to the system.

View File

@ -7,7 +7,7 @@ import (
"path/filepath" "path/filepath"
"syscall" "syscall"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
/* To pass into syscall, we need a struct matching the following: /* To pass into syscall, we need a struct matching the following:

View File

@ -23,6 +23,13 @@ var mutatedUtilityVMFiles = map[string]bool{
`EFI\Microsoft\Boot\BCD.LOG2`: true, `EFI\Microsoft\Boot\BCD.LOG2`: true,
} }
const (
filesPath = `Files`
hivesPath = `Hives`
utilityVMPath = `UtilityVM`
utilityVMFilesPath = `UtilityVM\Files`
)
func openFileOrDir(path string, mode uint32, createDisposition uint32) (file *os.File, err error) { func openFileOrDir(path string, mode uint32, createDisposition uint32) (file *os.File, err error) {
return winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createDisposition) return winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createDisposition)
} }
@ -44,6 +51,10 @@ func makeLongAbsPath(path string) (string, error) {
return `\\?\` + path, nil return `\\?\` + path, nil
} }
func hasPathPrefix(p, prefix string) bool {
return strings.HasPrefix(p, prefix) && len(p) > len(prefix) && p[len(prefix)] == '\\'
}
type fileEntry struct { type fileEntry struct {
path string path string
fi os.FileInfo fi os.FileInfo
@ -83,7 +94,7 @@ func readTombstones(path string) (map[string]([]string), error) {
ts := make(map[string]([]string)) ts := make(map[string]([]string))
for s.Scan() { for s.Scan() {
t := filepath.Join("Files", s.Text()[1:]) // skip leading `\` t := filepath.Join(filesPath, s.Text()[1:]) // skip leading `\`
dir := filepath.Dir(t) dir := filepath.Dir(t)
ts[dir] = append(ts[dir], t) ts[dir] = append(ts[dir], t)
} }
@ -212,7 +223,7 @@ func (r *legacyLayerReader) Next() (path string, size int64, fileInfo *winio.Fil
return return
} }
if fe.fi.IsDir() && strings.HasPrefix(path, `Files\`) { if fe.fi.IsDir() && hasPathPrefix(path, filesPath) {
fe.path += ".$wcidirs$" fe.path += ".$wcidirs$"
} }
@ -231,14 +242,14 @@ func (r *legacyLayerReader) Next() (path string, size int64, fileInfo *winio.Fil
return return
} }
if !strings.HasPrefix(path, `Files\`) { if !hasPathPrefix(path, filesPath) {
size = fe.fi.Size() size = fe.fi.Size()
r.backupReader = winio.NewBackupFileReader(f, false) r.backupReader = winio.NewBackupFileReader(f, false)
if path == "Hives" || path == "Files" { if path == hivesPath || path == filesPath {
// The Hives directory has a non-deterministic file time because of the // The Hives directory has a non-deterministic file time because of the
// nature of the import process. Use the times from System_Delta. // nature of the import process. Use the times from System_Delta.
var g *os.File var g *os.File
g, err = os.Open(filepath.Join(r.root, `Hives\System_Delta`)) g, err = os.Open(filepath.Join(r.root, hivesPath, `System_Delta`))
if err != nil { if err != nil {
return return
} }
@ -357,7 +368,7 @@ func (w *legacyLayerWriter) init() error {
func (w *legacyLayerWriter) initUtilityVM() error { func (w *legacyLayerWriter) initUtilityVM() error {
if !w.HasUtilityVM { if !w.HasUtilityVM {
err := os.Mkdir(filepath.Join(w.destRoot, `UtilityVM`), 0) err := os.Mkdir(filepath.Join(w.destRoot, utilityVMPath), 0)
if err != nil { if err != nil {
return err return err
} }
@ -365,7 +376,7 @@ func (w *legacyLayerWriter) initUtilityVM() error {
// clone the utility VM from the parent layer into this layer. Use hard // clone the utility VM from the parent layer into this layer. Use hard
// links to avoid unnecessary copying, since most of the files are // links to avoid unnecessary copying, since most of the files are
// immutable. // immutable.
err = cloneTree(filepath.Join(w.parentRoots[0], `UtilityVM\Files`), filepath.Join(w.destRoot, `UtilityVM\Files`), mutatedUtilityVMFiles) err = cloneTree(filepath.Join(w.parentRoots[0], utilityVMFilesPath), filepath.Join(w.destRoot, utilityVMFilesPath), mutatedUtilityVMFiles)
if err != nil { if err != nil {
return fmt.Errorf("cloning the parent utility VM image failed: %s", err) return fmt.Errorf("cloning the parent utility VM image failed: %s", err)
} }
@ -490,15 +501,15 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
return err return err
} }
if name == `UtilityVM` { if name == utilityVMPath {
return w.initUtilityVM() return w.initUtilityVM()
} }
if strings.HasPrefix(name, `UtilityVM\`) { if hasPathPrefix(name, utilityVMPath) {
if !w.HasUtilityVM { if !w.HasUtilityVM {
return errors.New("missing UtilityVM directory") return errors.New("missing UtilityVM directory")
} }
if !strings.HasPrefix(name, `UtilityVM\Files\`) && name != `UtilityVM\Files` { if !hasPathPrefix(name, utilityVMFilesPath) && name != utilityVMFilesPath {
return errors.New("invalid UtilityVM layer") return errors.New("invalid UtilityVM layer")
} }
path := filepath.Join(w.destRoot, name) path := filepath.Join(w.destRoot, name)
@ -585,7 +596,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
return err return err
} }
if strings.HasPrefix(name, `Hives\`) { if hasPathPrefix(name, hivesPath) {
w.backupWriter = winio.NewBackupFileWriter(f, false) w.backupWriter = winio.NewBackupFileWriter(f, false)
} else { } else {
// The file attributes are written before the stream. // The file attributes are written before the stream.
@ -608,22 +619,19 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error {
return err return err
} }
var requiredPrefix string
var roots []string var roots []string
if prefix := `Files\`; strings.HasPrefix(name, prefix) { if hasPathPrefix(target, filesPath) {
requiredPrefix = prefix
// Look for cross-layer hard link targets in the parent layers, since // Look for cross-layer hard link targets in the parent layers, since
// nothing is in the destination path yet. // nothing is in the destination path yet.
roots = w.parentRoots roots = w.parentRoots
} else if prefix := `UtilityVM\Files\`; strings.HasPrefix(name, prefix) { } else if hasPathPrefix(target, utilityVMFilesPath) {
requiredPrefix = prefix
// Since the utility VM is fully cloned into the destination path // Since the utility VM is fully cloned into the destination path
// already, look for cross-layer hard link targets directly in the // already, look for cross-layer hard link targets directly in the
// destination path. // destination path.
roots = []string{w.destRoot} roots = []string{w.destRoot}
} }
if requiredPrefix == "" || !strings.HasPrefix(target, requiredPrefix) { if roots == nil || (!hasPathPrefix(name, filesPath) && !hasPathPrefix(name, utilityVMFilesPath)) {
return errors.New("invalid hard link in layer") return errors.New("invalid hard link in layer")
} }
@ -657,9 +665,9 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error {
} }
func (w *legacyLayerWriter) Remove(name string) error { func (w *legacyLayerWriter) Remove(name string) error {
if strings.HasPrefix(name, `Files\`) { if hasPathPrefix(name, filesPath) {
w.tombstones = append(w.tombstones, name[len(`Files\`):]) w.tombstones = append(w.tombstones, name[len(filesPath)+1:])
} else if strings.HasPrefix(name, `UtilityVM\Files\`) { } else if hasPathPrefix(name, utilityVMFilesPath) {
err := w.initUtilityVM() err := w.initUtilityVM()
if err != nil { if err != nil {
return err return err

View File

@ -0,0 +1,934 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
/*
mksyscall_windows generates windows system call bodies
It parses all files specified on command line containing function
prototypes (like syscall_windows.go) and prints system call bodies
to standard output.
The prototypes are marked by lines beginning with "//sys" and read
like func declarations if //sys is replaced by func, but:
* The parameter lists must give a name for each argument. This
includes return parameters.
* The parameter lists must give a type for each argument:
the (x, y, z int) shorthand is not allowed.
* If the return parameter is an error number, it must be named err.
* If go func name needs to be different from it's winapi dll name,
the winapi name could be specified at the end, after "=" sign, like
//sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
* Each function that returns err needs to supply a condition, that
return value of winapi will be tested against to detect failure.
This would set err to windows "last-error", otherwise it will be nil.
The value can be provided at end of //sys declaration, like
//sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
and is [failretval==0] by default.
Usage:
mksyscall_windows [flags] [path ...]
The flags are:
-output
Specify output file name (outputs to console if blank).
-trace
Generate print statement after every syscall.
*/
package main
import (
"bufio"
"bytes"
"errors"
"flag"
"fmt"
"go/format"
"go/parser"
"go/token"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
"text/template"
)
var (
filename = flag.String("output", "", "output file name (standard output if omitted)")
printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
systemDLL = flag.Bool("systemdll", true, "whether all DLLs should be loaded from the Windows system directory")
)
func trim(s string) string {
return strings.Trim(s, " \t")
}
var packageName string
func packagename() string {
return packageName
}
func syscalldot() string {
if packageName == "syscall" {
return ""
}
return "syscall."
}
// Param is function parameter
type Param struct {
Name string
Type string
fn *Fn
tmpVarIdx int
}
// tmpVar returns temp variable name that will be used to represent p during syscall.
func (p *Param) tmpVar() string {
if p.tmpVarIdx < 0 {
p.tmpVarIdx = p.fn.curTmpVarIdx
p.fn.curTmpVarIdx++
}
return fmt.Sprintf("_p%d", p.tmpVarIdx)
}
// BoolTmpVarCode returns source code for bool temp variable.
func (p *Param) BoolTmpVarCode() string {
const code = `var %s uint32
if %s {
%s = 1
} else {
%s = 0
}`
tmp := p.tmpVar()
return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
}
// SliceTmpVarCode returns source code for slice temp variable.
func (p *Param) SliceTmpVarCode() string {
const code = `var %s *%s
if len(%s) > 0 {
%s = &%s[0]
}`
tmp := p.tmpVar()
return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
}
// StringTmpVarCode returns source code for string temp variable.
func (p *Param) StringTmpVarCode() string {
errvar := p.fn.Rets.ErrorVarName()
if errvar == "" {
errvar = "_"
}
tmp := p.tmpVar()
const code = `var %s %s
%s, %s = %s(%s)`
s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
if errvar == "-" {
return s
}
const morecode = `
if %s != nil {
return
}`
return s + fmt.Sprintf(morecode, errvar)
}
// TmpVarCode returns source code for temp variable.
func (p *Param) TmpVarCode() string {
switch {
case p.Type == "bool":
return p.BoolTmpVarCode()
case strings.HasPrefix(p.Type, "[]"):
return p.SliceTmpVarCode()
default:
return ""
}
}
// TmpVarHelperCode returns source code for helper's temp variable.
func (p *Param) TmpVarHelperCode() string {
if p.Type != "string" {
return ""
}
return p.StringTmpVarCode()
}
// SyscallArgList returns source code fragments representing p parameter
// in syscall. Slices are translated into 2 syscall parameters: pointer to
// the first element and length.
func (p *Param) SyscallArgList() []string {
t := p.HelperType()
var s string
switch {
case t[0] == '*':
s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
case t == "bool":
s = p.tmpVar()
case strings.HasPrefix(t, "[]"):
return []string{
fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
fmt.Sprintf("uintptr(len(%s))", p.Name),
}
default:
s = p.Name
}
return []string{fmt.Sprintf("uintptr(%s)", s)}
}
// IsError determines if p parameter is used to return error.
func (p *Param) IsError() bool {
return p.Name == "err" && p.Type == "error"
}
// HelperType returns type of parameter p used in helper function.
func (p *Param) HelperType() string {
if p.Type == "string" {
return p.fn.StrconvType()
}
return p.Type
}
// join concatenates parameters ps into a string with sep separator.
// Each parameter is converted into string by applying fn to it
// before conversion.
func join(ps []*Param, fn func(*Param) string, sep string) string {
if len(ps) == 0 {
return ""
}
a := make([]string, 0)
for _, p := range ps {
a = append(a, fn(p))
}
return strings.Join(a, sep)
}
// Rets describes function return parameters.
type Rets struct {
Name string
Type string
ReturnsError bool
FailCond string
}
// ErrorVarName returns error variable name for r.
func (r *Rets) ErrorVarName() string {
if r.ReturnsError {
return "err"
}
if r.Type == "error" {
return r.Name
}
return ""
}
// ToParams converts r into slice of *Param.
func (r *Rets) ToParams() []*Param {
ps := make([]*Param, 0)
if len(r.Name) > 0 {
ps = append(ps, &Param{Name: r.Name, Type: r.Type})
}
if r.ReturnsError {
ps = append(ps, &Param{Name: "err", Type: "error"})
}
return ps
}
// List returns source code of syscall return parameters.
func (r *Rets) List() string {
s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
if len(s) > 0 {
s = "(" + s + ")"
}
return s
}
// PrintList returns source code of trace printing part correspondent
// to syscall return values.
func (r *Rets) PrintList() string {
return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
}
// SetReturnValuesCode returns source code that accepts syscall return values.
func (r *Rets) SetReturnValuesCode() string {
if r.Name == "" && !r.ReturnsError {
return ""
}
retvar := "r0"
if r.Name == "" {
retvar = "r1"
}
errvar := "_"
if r.ReturnsError {
errvar = "e1"
}
return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
}
func (r *Rets) useLongHandleErrorCode(retvar string) string {
const code = `if %s {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = %sEINVAL
}
}`
cond := retvar + " == 0"
if r.FailCond != "" {
cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
}
return fmt.Sprintf(code, cond, syscalldot())
}
// SetErrorCode returns source code that sets return parameters.
func (r *Rets) SetErrorCode() string {
const code = `if r0 != 0 {
%s = %sErrno(r0)
}`
const hrCode = `if int32(r0) < 0 {
%s = %sErrno(win32FromHresult(r0))
}`
if r.Name == "" && !r.ReturnsError {
return ""
}
if r.Name == "" {
return r.useLongHandleErrorCode("r1")
}
if r.Type == "error" {
if r.Name == "hr" {
return fmt.Sprintf(hrCode, r.Name, syscalldot())
} else {
return fmt.Sprintf(code, r.Name, syscalldot())
}
}
s := ""
switch {
case r.Type[0] == '*':
s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
case r.Type == "bool":
s = fmt.Sprintf("%s = r0 != 0", r.Name)
default:
s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
}
if !r.ReturnsError {
return s
}
return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
}
// Fn describes syscall function.
type Fn struct {
Name string
Params []*Param
Rets *Rets
PrintTrace bool
confirmproc bool
dllname string
dllfuncname string
src string
// TODO: get rid of this field and just use parameter index instead
curTmpVarIdx int // insure tmp variables have uniq names
}
// extractParams parses s to extract function parameters.
func extractParams(s string, f *Fn) ([]*Param, error) {
s = trim(s)
if s == "" {
return nil, nil
}
a := strings.Split(s, ",")
ps := make([]*Param, len(a))
for i := range ps {
s2 := trim(a[i])
b := strings.Split(s2, " ")
if len(b) != 2 {
b = strings.Split(s2, "\t")
if len(b) != 2 {
return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
}
}
ps[i] = &Param{
Name: trim(b[0]),
Type: trim(b[1]),
fn: f,
tmpVarIdx: -1,
}
}
return ps, nil
}
// extractSection extracts text out of string s starting after start
// and ending just before end. found return value will indicate success,
// and prefix, body and suffix will contain correspondent parts of string s.
func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
s = trim(s)
if strings.HasPrefix(s, string(start)) {
// no prefix
body = s[1:]
} else {
a := strings.SplitN(s, string(start), 2)
if len(a) != 2 {
return "", "", s, false
}
prefix = a[0]
body = a[1]
}
a := strings.SplitN(body, string(end), 2)
if len(a) != 2 {
return "", "", "", false
}
return prefix, a[0], a[1], true
}
// newFn parses string s and return created function Fn.
func newFn(s string) (*Fn, error) {
s = trim(s)
f := &Fn{
Rets: &Rets{},
src: s,
PrintTrace: *printTraceFlag,
}
// function name and args
prefix, body, s, found := extractSection(s, '(', ')')
if !found || prefix == "" {
return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
}
f.Name = prefix
var err error
f.Params, err = extractParams(body, f)
if err != nil {
return nil, err
}
// return values
_, body, s, found = extractSection(s, '(', ')')
if found {
r, err := extractParams(body, f)
if err != nil {
return nil, err
}
switch len(r) {
case 0:
case 1:
if r[0].IsError() {
f.Rets.ReturnsError = true
} else {
f.Rets.Name = r[0].Name
f.Rets.Type = r[0].Type
}
case 2:
if !r[1].IsError() {
return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
}
f.Rets.ReturnsError = true
f.Rets.Name = r[0].Name
f.Rets.Type = r[0].Type
default:
return nil, errors.New("Too many return values in \"" + f.src + "\"")
}
}
// fail condition
_, body, s, found = extractSection(s, '[', ']')
if found {
f.Rets.FailCond = body
}
// dll and dll function names
s = trim(s)
if s == "" {
return f, nil
}
if !strings.HasPrefix(s, "=") {
return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
}
s = trim(s[1:])
a := strings.Split(s, ".")
switch len(a) {
case 1:
f.dllfuncname = a[0]
case 2:
f.dllname = a[0]
f.dllfuncname = a[1]
default:
return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
}
if f.dllfuncname[len(f.dllfuncname)-1] == '?' {
f.confirmproc = true
f.dllfuncname = f.dllfuncname[0 : len(f.dllfuncname)-1]
}
return f, nil
}
// DLLName returns DLL name for function f.
func (f *Fn) DLLName() string {
if f.dllname == "" {
return "kernel32"
}
return f.dllname
}
// DLLName returns DLL function name for function f.
func (f *Fn) DLLFuncName() string {
if f.dllfuncname == "" {
return f.Name
}
return f.dllfuncname
}
func (f *Fn) ConfirmProc() bool {
return f.confirmproc
}
// ParamList returns source code for function f parameters.
func (f *Fn) ParamList() string {
return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
}
// HelperParamList returns source code for helper function f parameters.
func (f *Fn) HelperParamList() string {
return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ")
}
// ParamPrintList returns source code of trace printing part correspondent
// to syscall input parameters.
func (f *Fn) ParamPrintList() string {
return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
}
// ParamCount return number of syscall parameters for function f.
func (f *Fn) ParamCount() int {
n := 0
for _, p := range f.Params {
n += len(p.SyscallArgList())
}
return n
}
// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
// to use. It returns parameter count for correspondent SyscallX function.
func (f *Fn) SyscallParamCount() int {
n := f.ParamCount()
switch {
case n <= 3:
return 3
case n <= 6:
return 6
case n <= 9:
return 9
case n <= 12:
return 12
case n <= 15:
return 15
default:
panic("too many arguments to system call")
}
}
// Syscall determines which SyscallX function to use for function f.
func (f *Fn) Syscall() string {
c := f.SyscallParamCount()
if c == 3 {
return syscalldot() + "Syscall"
}
return syscalldot() + "Syscall" + strconv.Itoa(c)
}
// SyscallParamList returns source code for SyscallX parameters for function f.
func (f *Fn) SyscallParamList() string {
a := make([]string, 0)
for _, p := range f.Params {
a = append(a, p.SyscallArgList()...)
}
for len(a) < f.SyscallParamCount() {
a = append(a, "0")
}
return strings.Join(a, ", ")
}
// HelperCallParamList returns source code of call into function f helper.
func (f *Fn) HelperCallParamList() string {
a := make([]string, 0, len(f.Params))
for _, p := range f.Params {
s := p.Name
if p.Type == "string" {
s = p.tmpVar()
}
a = append(a, s)
}
return strings.Join(a, ", ")
}
// IsUTF16 is true, if f is W (utf16) function. It is false
// for all A (ascii) functions.
func (_ *Fn) IsUTF16() bool {
return true
}
// StrconvFunc returns name of Go string to OS string function for f.
func (f *Fn) StrconvFunc() string {
if f.IsUTF16() {
return syscalldot() + "UTF16PtrFromString"
}
return syscalldot() + "BytePtrFromString"
}
// StrconvType returns Go type name used for OS string for f.
func (f *Fn) StrconvType() string {
if f.IsUTF16() {
return "*uint16"
}
return "*byte"
}
// HasStringParam is true, if f has at least one string parameter.
// Otherwise it is false.
func (f *Fn) HasStringParam() bool {
for _, p := range f.Params {
if p.Type == "string" {
return true
}
}
return false
}
var uniqDllFuncName = make(map[string]bool)
// IsNotDuplicate is true if f is not a duplicated function
func (f *Fn) IsNotDuplicate() bool {
funcName := f.DLLFuncName()
if uniqDllFuncName[funcName] == false {
uniqDllFuncName[funcName] = true
return true
}
return false
}
// HelperName returns name of function f helper.
func (f *Fn) HelperName() string {
if !f.HasStringParam() {
return f.Name
}
return "_" + f.Name
}
// Source files and functions.
type Source struct {
Funcs []*Fn
Files []string
StdLibImports []string
ExternalImports []string
}
func (src *Source) Import(pkg string) {
src.StdLibImports = append(src.StdLibImports, pkg)
sort.Strings(src.StdLibImports)
}
func (src *Source) ExternalImport(pkg string) {
src.ExternalImports = append(src.ExternalImports, pkg)
sort.Strings(src.ExternalImports)
}
// ParseFiles parses files listed in fs and extracts all syscall
// functions listed in sys comments. It returns source files
// and functions collection *Source if successful.
func ParseFiles(fs []string) (*Source, error) {
src := &Source{
Funcs: make([]*Fn, 0),
Files: make([]string, 0),
StdLibImports: []string{
"unsafe",
},
ExternalImports: make([]string, 0),
}
for _, file := range fs {
if err := src.ParseFile(file); err != nil {
return nil, err
}
}
return src, nil
}
// DLLs return dll names for a source set src.
func (src *Source) DLLs() []string {
uniq := make(map[string]bool)
r := make([]string, 0)
for _, f := range src.Funcs {
name := f.DLLName()
if _, found := uniq[name]; !found {
uniq[name] = true
r = append(r, name)
}
}
return r
}
// ParseFile adds additional file path to a source set src.
func (src *Source) ParseFile(path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
s := bufio.NewScanner(file)
for s.Scan() {
t := trim(s.Text())
if len(t) < 7 {
continue
}
if !strings.HasPrefix(t, "//sys") {
continue
}
t = t[5:]
if !(t[0] == ' ' || t[0] == '\t') {
continue
}
f, err := newFn(t[1:])
if err != nil {
return err
}
src.Funcs = append(src.Funcs, f)
}
if err := s.Err(); err != nil {
return err
}
src.Files = append(src.Files, path)
// get package name
fset := token.NewFileSet()
_, err = file.Seek(0, 0)
if err != nil {
return err
}
pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly)
if err != nil {
return err
}
packageName = pkg.Name.Name
return nil
}
// IsStdRepo returns true if src is part of standard library.
func (src *Source) IsStdRepo() (bool, error) {
if len(src.Files) == 0 {
return false, errors.New("no input files provided")
}
abspath, err := filepath.Abs(src.Files[0])
if err != nil {
return false, err
}
goroot := runtime.GOROOT()
if runtime.GOOS == "windows" {
abspath = strings.ToLower(abspath)
goroot = strings.ToLower(goroot)
}
sep := string(os.PathSeparator)
if !strings.HasSuffix(goroot, sep) {
goroot += sep
}
return strings.HasPrefix(abspath, goroot), nil
}
// Generate output source file from a source set src.
func (src *Source) Generate(w io.Writer) error {
const (
pkgStd = iota // any package in std library
pkgXSysWindows // x/sys/windows package
pkgOther
)
isStdRepo, err := src.IsStdRepo()
if err != nil {
return err
}
var pkgtype int
switch {
case isStdRepo:
pkgtype = pkgStd
case packageName == "windows":
// TODO: this needs better logic than just using package name
pkgtype = pkgXSysWindows
default:
pkgtype = pkgOther
}
if *systemDLL {
switch pkgtype {
case pkgStd:
src.Import("internal/syscall/windows/sysdll")
case pkgXSysWindows:
default:
src.ExternalImport("golang.org/x/sys/windows")
}
}
src.ExternalImport("github.com/Microsoft/go-winio")
if packageName != "syscall" {
src.Import("syscall")
}
funcMap := template.FuncMap{
"packagename": packagename,
"syscalldot": syscalldot,
"newlazydll": func(dll string) string {
arg := "\"" + dll + ".dll\""
if !*systemDLL {
return syscalldot() + "NewLazyDLL(" + arg + ")"
}
switch pkgtype {
case pkgStd:
return syscalldot() + "NewLazyDLL(sysdll.Add(" + arg + "))"
case pkgXSysWindows:
return "NewLazySystemDLL(" + arg + ")"
default:
return "windows.NewLazySystemDLL(" + arg + ")"
}
},
}
t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
err = t.Execute(w, src)
if err != nil {
return errors.New("Failed to execute template: " + err.Error())
}
return nil
}
func usage() {
fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
flag.PrintDefaults()
os.Exit(1)
}
func main() {
flag.Usage = usage
flag.Parse()
if len(flag.Args()) <= 0 {
fmt.Fprintf(os.Stderr, "no files to parse provided\n")
usage()
}
src, err := ParseFiles(flag.Args())
if err != nil {
log.Fatal(err)
}
var buf bytes.Buffer
if err := src.Generate(&buf); err != nil {
log.Fatal(err)
}
data, err := format.Source(buf.Bytes())
if err != nil {
log.Fatal(err)
}
if *filename == "" {
_, err = os.Stdout.Write(data)
} else {
err = ioutil.WriteFile(*filename, data, 0644)
}
if err != nil {
log.Fatal(err)
}
}
// TODO: use println instead to print in the following template
const srcTemplate = `
{{define "main"}}// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
package {{packagename}}
import (
{{range .StdLibImports}}"{{.}}"
{{end}}
{{range .ExternalImports}}"{{.}}"
{{end}}
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = {{syscalldot}}Errno(errnoERROR_IO_PENDING)
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e {{syscalldot}}Errno) error {
switch e {
case 0:
return nil
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
{{template "dlls" .}}
{{template "funcnames" .}})
{{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}}
{{end}}
{{/* help functions */}}
{{define "dlls"}}{{range .DLLs}} mod{{.}} = {{newlazydll .}}
{{end}}{{end}}
{{define "funcnames"}}{{range .Funcs}}{{if .IsNotDuplicate}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}"){{end}}
{{end}}{{end}}
{{define "helperbody"}}
func {{.Name}}({{.ParamList}}) {{template "results" .}}{
{{template "helpertmpvars" .}} return {{.HelperName}}({{.HelperCallParamList}})
}
{{end}}
{{define "funcbody"}}
func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
{{template "tmpvars" .}} {{template "syscallcheck" .}}{{template "syscall" .}}
{{template "seterror" .}}{{template "printtrace" .}} return
}
{{end}}
{{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}} {{.TmpVarHelperCode}}
{{end}}{{end}}{{end}}
{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}} {{.TmpVarCode}}
{{end}}{{end}}{{end}}
{{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
{{define "syscallcheck"}}{{if .ConfirmProc}}if {{.Rets.ErrorVarName}} = proc{{.DLLFuncName}}.Find(); {{.Rets.ErrorVarName}} != nil {
return
}
{{end}}{{end}}
{{define "seterror"}}{{if .Rets.SetErrorCode}} {{.Rets.SetErrorCode}}
{{end}}{{end}}
{{define "printtrace"}}{{if .PrintTrace}} print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
{{end}}{{end}}
`

View File

@ -1,6 +1,6 @@
package hcsshim package hcsshim
import "github.com/Sirupsen/logrus" import "github.com/sirupsen/logrus"
// NameToGuid converts the given string into a GUID using the algorithm in the // NameToGuid converts the given string into a GUID using the algorithm in the
// Host Compute Service, ensuring GUIDs generated with the same string are common // Host Compute Service, ensuring GUIDs generated with the same string are common

View File

@ -3,7 +3,7 @@ package hcsshim
import ( import (
"sync" "sync"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var prepareLayerLock sync.Mutex var prepareLayerLock sync.Mutex

View File

@ -3,12 +3,11 @@ package hcsshim
import ( import (
"encoding/json" "encoding/json"
"io" "io"
"runtime"
"sync" "sync"
"syscall" "syscall"
"time" "time"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// ContainerError is an error encountered in HCS // ContainerError is an error encountered in HCS
@ -322,17 +321,11 @@ func (process *process) Close() error {
} }
process.handle = 0 process.handle = 0
runtime.SetFinalizer(process, nil)
logrus.Debugf(title+" succeeded processid=%d", process.processID) logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
// closeProcess wraps process.Close for use by a finalizer
func closeProcess(process *process) {
process.Close()
}
func (process *process) registerCallback() error { func (process *process) registerCallback() error {
context := &notifcationWatcherContext{ context := &notifcationWatcherContext{
channels: newChannels(), channels: newChannels(),

View File

@ -1,6 +1,6 @@
package hcsshim package hcsshim
import "github.com/Sirupsen/logrus" import "github.com/sirupsen/logrus"
// UnprepareLayer disables the filesystem filter for the read-write layer with // UnprepareLayer disables the filesystem filter for the read-write layer with
// the given id. // the given id.

View File

@ -3,7 +3,7 @@ package hcsshim
import ( import (
"time" "time"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
func processAsyncHcsResult(err error, resultp *uint16, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error { func processAsyncHcsResult(err error, resultp *uint16, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error {
@ -59,4 +59,5 @@ func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotific
case <-c: case <-c:
return ErrTimeout return ErrTimeout
} }
return nil
} }

View File

@ -1,41 +0,0 @@
package logrus
import (
"encoding/json"
"fmt"
)
type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string
}
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data := make(Fields, len(entry.Data)+3)
for k, v := range entry.Data {
switch v := v.(type) {
case error:
// Otherwise errors are ignored by `encoding/json`
// https://github.com/Sirupsen/logrus/issues/137
data[k] = v.Error()
default:
data[k] = v
}
}
prefixFieldClashes(data)
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat
}
data["time"] = entry.Time.Format(timestampFormat)
data["msg"] = entry.Message
data["level"] = entry.Level.String()
serialized, err := json.Marshal(data)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
return append(serialized, '\n'), nil
}

View File

@ -1,15 +0,0 @@
// +build solaris,!appengine
package logrus
import (
"os"
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal() bool {
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
return err == nil
}

View File

@ -1,27 +0,0 @@
// Based on ssh/terminal:
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows,!appengine
package logrus
import (
"syscall"
"unsafe"
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
)
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool {
fd := syscall.Stderr
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"sync" "sync"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// Broadcaster sends events to multiple, reliable Sinks. The goal of this // Broadcaster sends events to multiple, reliable Sinks. The goal of this

View File

@ -4,7 +4,7 @@ import (
"container/list" "container/list"
"sync" "sync"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// Queue accepts all messages into a queue for asynchronous consumption // Queue accepts all messages into a queue for asynchronous consumption

View File

@ -7,7 +7,7 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/Sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// RetryingSink retries the write until success or an ErrSinkClosed is // RetryingSink retries the write until success or an ErrSinkClosed is

View File

@ -1,4 +1,4 @@
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus) # Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus)
Logrus is a structured logger for Go (golang), completely API compatible with Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
@ -7,6 +7,17 @@ many large deployments. The core API is unlikely to change much but please
version control your Logrus to make sure you aren't fetching latest `master` on version control your Logrus to make sure you aren't fetching latest `master` on
every build.** every build.**
**Seeing weird case-sensitive problems?** Unfortunately, the author failed to
realize the consequences of renaming to lower-case. Due to the Go package
environment, this caused issues. Regretfully, there's no turning back now.
Everything using `logrus` will need to use the lower-case:
`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
I am terribly sorry for this inconvenience. Logrus strives hard for backwards
compatibility, and the author failed to realize the cascading consequences of
such a name-change. To fix Glide, see [these
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
Nicely color-coded in development (when a TTY is attached, otherwise just Nicely color-coded in development (when a TTY is attached, otherwise just
plain text): plain text):
@ -46,6 +57,12 @@ time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x20822
exit status 1 exit status 1
``` ```
#### Case-sensitivity
The organization's name was changed to lower-case--and this will not be changed
back. If you are getting import conflicts due to case sensitivity, please use
the lower-case import: `github.com/sirupsen/logrus`.
#### Example #### Example
The simplest way to use Logrus is simply the package-level exported logger: The simplest way to use Logrus is simply the package-level exported logger:
@ -54,7 +71,7 @@ The simplest way to use Logrus is simply the package-level exported logger:
package main package main
import ( import (
log "github.com/Sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
func main() { func main() {
@ -65,7 +82,7 @@ func main() {
``` ```
Note that it's completely api-compatible with the stdlib logger, so you can Note that it's completely api-compatible with the stdlib logger, so you can
replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"` replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"`
and you'll now have the flexibility of Logrus. You can customize it all you and you'll now have the flexibility of Logrus. You can customize it all you
want: want:
@ -74,15 +91,16 @@ package main
import ( import (
"os" "os"
log "github.com/Sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
func init() { func init() {
// Log as JSON instead of the default ASCII formatter. // Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{}) log.SetFormatter(&log.JSONFormatter{})
// Output to stderr instead of stdout, could also be a file. // Output to stdout instead of the default stderr
log.SetOutput(os.Stderr) // Can be any io.Writer, see below for File example
log.SetOutput(os.Stdout)
// Only log the warning severity or above. // Only log the warning severity or above.
log.SetLevel(log.WarnLevel) log.SetLevel(log.WarnLevel)
@ -123,7 +141,8 @@ application, you can also create an instance of the `logrus` Logger:
package main package main
import ( import (
"github.com/Sirupsen/logrus" "os"
"github.com/sirupsen/logrus"
) )
// Create a new instance of the logger. You can have any number of instances. // Create a new instance of the logger. You can have any number of instances.
@ -132,7 +151,15 @@ var log = logrus.New()
func main() { func main() {
// The API for setting attributes is a little different than the package level // The API for setting attributes is a little different than the package level
// exported logger. See Godoc. // exported logger. See Godoc.
log.Out = os.Stderr log.Out = os.Stdout
// You could set this to any `io.Writer` such as a file
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
// if err == nil {
// log.Out = file
// } else {
// log.Info("Failed to log to file, using default stderr")
// }
log.WithFields(logrus.Fields{ log.WithFields(logrus.Fields{
"animal": "walrus", "animal": "walrus",
@ -143,7 +170,7 @@ func main() {
#### Fields #### Fields
Logrus encourages careful, structured logging though logging fields instead of Logrus encourages careful, structured logging through logging fields instead of
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
to send event %s to topic %s with key %d")`, you should log the much more to send event %s to topic %s with key %d")`, you should log the much more
discoverable: discoverable:
@ -165,6 +192,20 @@ In general, with Logrus using any of the `printf`-family functions should be
seen as a hint you should add a field, however, you can still use the seen as a hint you should add a field, however, you can still use the
`printf`-family functions with Logrus. `printf`-family functions with Logrus.
#### Default Fields
Often it's helpful to have fields _always_ attached to log statements in an
application or parts of one. For example, you may want to always log the
`request_id` and `user_ip` in the context of a request. Instead of writing
`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on
every line, you can create a `logrus.Entry` to pass around instead:
```go
requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
requestLogger.Info("something happened on that request") # will log request_id and user_ip
requestLogger.Warn("something not great happened")
```
#### Hooks #### Hooks
You can add hooks for logging levels. For example to send errors to an exception You can add hooks for logging levels. For example to send errors to an exception
@ -176,9 +217,9 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
```go ```go
import ( import (
log "github.com/Sirupsen/logrus" log "github.com/sirupsen/logrus"
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake" "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog" logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
"log/syslog" "log/syslog"
) )
@ -200,40 +241,51 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
| Hook | Description | | Hook | Description |
| ----- | ----------- | | ----- | ----------- |
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. | | [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. | | [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. | | [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) |
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) | | [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka | | [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) | | [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) |
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch| | [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)| | [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/)
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)| | [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) | | [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) |
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash | | [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) |
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) | | [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) | | [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. |
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
| [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) |
#### Level logging #### Level logging
@ -282,7 +334,7 @@ could do:
```go ```go
import ( import (
log "github.com/Sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
init() { init() {
@ -309,8 +361,11 @@ The built-in logging formatters are:
without colors. without colors.
* *Note:* to force colored output when there is no TTY, set the `ForceColors` * *Note:* to force colored output when there is no TTY, set the `ForceColors`
field to `true`. To force no colored output even if there is a TTY set the field to `true`. To force no colored output even if there is a TTY set the
`DisableColors` field to `true` `DisableColors` field to `true`. For Windows, see
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
* `logrus.JSONFormatter`. Logs fields as JSON. * `logrus.JSONFormatter`. Logs fields as JSON.
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
Third party logging formatters: Third party logging formatters:
@ -359,6 +414,18 @@ srv := http.Server{
Each line written to that writer will be printed the usual way, using formatters Each line written to that writer will be printed the usual way, using formatters
and hooks. The level for those entries is `info`. and hooks. The level for those entries is `info`.
This means that we can override the standard library logger easily:
```go
logger := logrus.New()
logger.Formatter = &logrus.JSONFormatter{}
// Use logrus for standard log output
// Note that `log` here references stdlib's log
// Not logrus imported under the name `log`.
log.SetOutput(logger.Writer())
```
#### Rotation #### Rotation
Log rotation is not provided with Logrus. Log rotation should be done by an Log rotation is not provided with Logrus. Log rotation should be done by an
@ -370,7 +437,7 @@ entries. It should not be a feature of the application-level logger.
| Tool | Description | | Tool | Description |
| ---- | ----------- | | ---- | ----------- |
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.| |[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper arround Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) | |[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
#### Testing #### Testing
@ -380,15 +447,24 @@ Logrus has a built in facility for asserting the presence of log messages. This
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): * a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
```go ```go
logger, hook := NewNullLogger() import(
logger.Error("Hello error") "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/null"
"github.com/stretchr/testify/assert"
"testing"
)
assert.Equal(1, len(hook.Entries)) func TestSomething(t*testing.T){
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level) logger, hook := null.NewNullLogger()
assert.Equal("Hello error", hook.LastEntry().Message) logger.Error("Helloerror")
hook.Reset() assert.Equal(t, 1, len(hook.Entries))
assert.Nil(hook.LastEntry()) assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level)
assert.Equal(t, "Helloerror", hook.LastEntry().Message)
hook.Reset()
assert.Nil(t, hook.LastEntry())
}
``` ```
#### Fatal handlers #### Fatal handlers
@ -407,7 +483,7 @@ logrus.RegisterExitHandler(handler)
... ...
``` ```
#### Thread safty #### Thread safety
By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs. By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.

View File

@ -1,7 +1,7 @@
package logrus package logrus
// The following code was sourced and modified from the // The following code was sourced and modified from the
// https://bitbucket.org/tebeka/atexit package governed by the following license: // https://github.com/tebeka/atexit package governed by the following license:
// //
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>. // Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
// //

View File

@ -7,7 +7,7 @@ The simplest way to use Logrus is simply the package-level exported logger:
package main package main
import ( import (
log "github.com/Sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
func main() { func main() {
@ -21,6 +21,6 @@ The simplest way to use Logrus is simply the package-level exported logger:
Output: Output:
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
For a full guide visit https://github.com/Sirupsen/logrus For a full guide visit https://github.com/sirupsen/logrus
*/ */
package logrus package logrus

View File

@ -126,7 +126,7 @@ func (entry Entry) log(level Level, msg string) {
} }
func (entry *Entry) Debug(args ...interface{}) { func (entry *Entry) Debug(args ...interface{}) {
if entry.Logger.Level >= DebugLevel { if entry.Logger.level() >= DebugLevel {
entry.log(DebugLevel, fmt.Sprint(args...)) entry.log(DebugLevel, fmt.Sprint(args...))
} }
} }
@ -136,13 +136,13 @@ func (entry *Entry) Print(args ...interface{}) {
} }
func (entry *Entry) Info(args ...interface{}) { func (entry *Entry) Info(args ...interface{}) {
if entry.Logger.Level >= InfoLevel { if entry.Logger.level() >= InfoLevel {
entry.log(InfoLevel, fmt.Sprint(args...)) entry.log(InfoLevel, fmt.Sprint(args...))
} }
} }
func (entry *Entry) Warn(args ...interface{}) { func (entry *Entry) Warn(args ...interface{}) {
if entry.Logger.Level >= WarnLevel { if entry.Logger.level() >= WarnLevel {
entry.log(WarnLevel, fmt.Sprint(args...)) entry.log(WarnLevel, fmt.Sprint(args...))
} }
} }
@ -152,20 +152,20 @@ func (entry *Entry) Warning(args ...interface{}) {
} }
func (entry *Entry) Error(args ...interface{}) { func (entry *Entry) Error(args ...interface{}) {
if entry.Logger.Level >= ErrorLevel { if entry.Logger.level() >= ErrorLevel {
entry.log(ErrorLevel, fmt.Sprint(args...)) entry.log(ErrorLevel, fmt.Sprint(args...))
} }
} }
func (entry *Entry) Fatal(args ...interface{}) { func (entry *Entry) Fatal(args ...interface{}) {
if entry.Logger.Level >= FatalLevel { if entry.Logger.level() >= FatalLevel {
entry.log(FatalLevel, fmt.Sprint(args...)) entry.log(FatalLevel, fmt.Sprint(args...))
} }
Exit(1) Exit(1)
} }
func (entry *Entry) Panic(args ...interface{}) { func (entry *Entry) Panic(args ...interface{}) {
if entry.Logger.Level >= PanicLevel { if entry.Logger.level() >= PanicLevel {
entry.log(PanicLevel, fmt.Sprint(args...)) entry.log(PanicLevel, fmt.Sprint(args...))
} }
panic(fmt.Sprint(args...)) panic(fmt.Sprint(args...))
@ -174,13 +174,13 @@ func (entry *Entry) Panic(args ...interface{}) {
// Entry Printf family functions // Entry Printf family functions
func (entry *Entry) Debugf(format string, args ...interface{}) { func (entry *Entry) Debugf(format string, args ...interface{}) {
if entry.Logger.Level >= DebugLevel { if entry.Logger.level() >= DebugLevel {
entry.Debug(fmt.Sprintf(format, args...)) entry.Debug(fmt.Sprintf(format, args...))
} }
} }
func (entry *Entry) Infof(format string, args ...interface{}) { func (entry *Entry) Infof(format string, args ...interface{}) {
if entry.Logger.Level >= InfoLevel { if entry.Logger.level() >= InfoLevel {
entry.Info(fmt.Sprintf(format, args...)) entry.Info(fmt.Sprintf(format, args...))
} }
} }
@ -190,7 +190,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) {
} }
func (entry *Entry) Warnf(format string, args ...interface{}) { func (entry *Entry) Warnf(format string, args ...interface{}) {
if entry.Logger.Level >= WarnLevel { if entry.Logger.level() >= WarnLevel {
entry.Warn(fmt.Sprintf(format, args...)) entry.Warn(fmt.Sprintf(format, args...))
} }
} }
@ -200,20 +200,20 @@ func (entry *Entry) Warningf(format string, args ...interface{}) {
} }
func (entry *Entry) Errorf(format string, args ...interface{}) { func (entry *Entry) Errorf(format string, args ...interface{}) {
if entry.Logger.Level >= ErrorLevel { if entry.Logger.level() >= ErrorLevel {
entry.Error(fmt.Sprintf(format, args...)) entry.Error(fmt.Sprintf(format, args...))
} }
} }
func (entry *Entry) Fatalf(format string, args ...interface{}) { func (entry *Entry) Fatalf(format string, args ...interface{}) {
if entry.Logger.Level >= FatalLevel { if entry.Logger.level() >= FatalLevel {
entry.Fatal(fmt.Sprintf(format, args...)) entry.Fatal(fmt.Sprintf(format, args...))
} }
Exit(1) Exit(1)
} }
func (entry *Entry) Panicf(format string, args ...interface{}) { func (entry *Entry) Panicf(format string, args ...interface{}) {
if entry.Logger.Level >= PanicLevel { if entry.Logger.level() >= PanicLevel {
entry.Panic(fmt.Sprintf(format, args...)) entry.Panic(fmt.Sprintf(format, args...))
} }
} }
@ -221,13 +221,13 @@ func (entry *Entry) Panicf(format string, args ...interface{}) {
// Entry Println family functions // Entry Println family functions
func (entry *Entry) Debugln(args ...interface{}) { func (entry *Entry) Debugln(args ...interface{}) {
if entry.Logger.Level >= DebugLevel { if entry.Logger.level() >= DebugLevel {
entry.Debug(entry.sprintlnn(args...)) entry.Debug(entry.sprintlnn(args...))
} }
} }
func (entry *Entry) Infoln(args ...interface{}) { func (entry *Entry) Infoln(args ...interface{}) {
if entry.Logger.Level >= InfoLevel { if entry.Logger.level() >= InfoLevel {
entry.Info(entry.sprintlnn(args...)) entry.Info(entry.sprintlnn(args...))
} }
} }
@ -237,7 +237,7 @@ func (entry *Entry) Println(args ...interface{}) {
} }
func (entry *Entry) Warnln(args ...interface{}) { func (entry *Entry) Warnln(args ...interface{}) {
if entry.Logger.Level >= WarnLevel { if entry.Logger.level() >= WarnLevel {
entry.Warn(entry.sprintlnn(args...)) entry.Warn(entry.sprintlnn(args...))
} }
} }
@ -247,20 +247,20 @@ func (entry *Entry) Warningln(args ...interface{}) {
} }
func (entry *Entry) Errorln(args ...interface{}) { func (entry *Entry) Errorln(args ...interface{}) {
if entry.Logger.Level >= ErrorLevel { if entry.Logger.level() >= ErrorLevel {
entry.Error(entry.sprintlnn(args...)) entry.Error(entry.sprintlnn(args...))
} }
} }
func (entry *Entry) Fatalln(args ...interface{}) { func (entry *Entry) Fatalln(args ...interface{}) {
if entry.Logger.Level >= FatalLevel { if entry.Logger.level() >= FatalLevel {
entry.Fatal(entry.sprintlnn(args...)) entry.Fatal(entry.sprintlnn(args...))
} }
Exit(1) Exit(1)
} }
func (entry *Entry) Panicln(args ...interface{}) { func (entry *Entry) Panicln(args ...interface{}) {
if entry.Logger.Level >= PanicLevel { if entry.Logger.level() >= PanicLevel {
entry.Panic(entry.sprintlnn(args...)) entry.Panic(entry.sprintlnn(args...))
} }
} }

View File

@ -31,14 +31,14 @@ func SetFormatter(formatter Formatter) {
func SetLevel(level Level) { func SetLevel(level Level) {
std.mu.Lock() std.mu.Lock()
defer std.mu.Unlock() defer std.mu.Unlock()
std.Level = level std.setLevel(level)
} }
// GetLevel returns the standard logger level. // GetLevel returns the standard logger level.
func GetLevel() Level { func GetLevel() Level {
std.mu.Lock() std.mu.Lock()
defer std.mu.Unlock() defer std.mu.Unlock()
return std.Level return std.level()
} }
// AddHook adds a hook to the standard logger hooks. // AddHook adds a hook to the standard logger hooks.

74
vendor/github.com/sirupsen/logrus/json_formatter.go generated vendored Normal file
View File

@ -0,0 +1,74 @@
package logrus
import (
"encoding/json"
"fmt"
)
type fieldKey string
type FieldMap map[fieldKey]string
const (
FieldKeyMsg = "msg"
FieldKeyLevel = "level"
FieldKeyTime = "time"
)
func (f FieldMap) resolve(key fieldKey) string {
if k, ok := f[key]; ok {
return k
}
return string(key)
}
type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string
// DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool
// FieldMap allows users to customize the names of keys for various fields.
// As an example:
// formatter := &JSONFormatter{
// FieldMap: FieldMap{
// FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level",
// FieldKeyMsg: "@message",
// },
// }
FieldMap FieldMap
}
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data := make(Fields, len(entry.Data)+3)
for k, v := range entry.Data {
switch v := v.(type) {
case error:
// Otherwise errors are ignored by `encoding/json`
// https://github.com/sirupsen/logrus/issues/137
data[k] = v.Error()
default:
data[k] = v
}
}
prefixFieldClashes(data)
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat
}
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()
serialized, err := json.Marshal(data)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
return append(serialized, '\n'), nil
}

View File

@ -4,6 +4,7 @@ import (
"io" "io"
"os" "os"
"sync" "sync"
"sync/atomic"
) )
type Logger struct { type Logger struct {
@ -112,7 +113,7 @@ func (logger *Logger) WithError(err error) *Entry {
} }
func (logger *Logger) Debugf(format string, args ...interface{}) { func (logger *Logger) Debugf(format string, args ...interface{}) {
if logger.Level >= DebugLevel { if logger.level() >= DebugLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Debugf(format, args...) entry.Debugf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -120,7 +121,7 @@ func (logger *Logger) Debugf(format string, args ...interface{}) {
} }
func (logger *Logger) Infof(format string, args ...interface{}) { func (logger *Logger) Infof(format string, args ...interface{}) {
if logger.Level >= InfoLevel { if logger.level() >= InfoLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Infof(format, args...) entry.Infof(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -134,7 +135,7 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
} }
func (logger *Logger) Warnf(format string, args ...interface{}) { func (logger *Logger) Warnf(format string, args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnf(format, args...) entry.Warnf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -142,7 +143,7 @@ func (logger *Logger) Warnf(format string, args ...interface{}) {
} }
func (logger *Logger) Warningf(format string, args ...interface{}) { func (logger *Logger) Warningf(format string, args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnf(format, args...) entry.Warnf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -150,7 +151,7 @@ func (logger *Logger) Warningf(format string, args ...interface{}) {
} }
func (logger *Logger) Errorf(format string, args ...interface{}) { func (logger *Logger) Errorf(format string, args ...interface{}) {
if logger.Level >= ErrorLevel { if logger.level() >= ErrorLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Errorf(format, args...) entry.Errorf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -158,7 +159,7 @@ func (logger *Logger) Errorf(format string, args ...interface{}) {
} }
func (logger *Logger) Fatalf(format string, args ...interface{}) { func (logger *Logger) Fatalf(format string, args ...interface{}) {
if logger.Level >= FatalLevel { if logger.level() >= FatalLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Fatalf(format, args...) entry.Fatalf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -167,7 +168,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) {
} }
func (logger *Logger) Panicf(format string, args ...interface{}) { func (logger *Logger) Panicf(format string, args ...interface{}) {
if logger.Level >= PanicLevel { if logger.level() >= PanicLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Panicf(format, args...) entry.Panicf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -175,7 +176,7 @@ func (logger *Logger) Panicf(format string, args ...interface{}) {
} }
func (logger *Logger) Debug(args ...interface{}) { func (logger *Logger) Debug(args ...interface{}) {
if logger.Level >= DebugLevel { if logger.level() >= DebugLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Debug(args...) entry.Debug(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -183,7 +184,7 @@ func (logger *Logger) Debug(args ...interface{}) {
} }
func (logger *Logger) Info(args ...interface{}) { func (logger *Logger) Info(args ...interface{}) {
if logger.Level >= InfoLevel { if logger.level() >= InfoLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Info(args...) entry.Info(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -197,7 +198,7 @@ func (logger *Logger) Print(args ...interface{}) {
} }
func (logger *Logger) Warn(args ...interface{}) { func (logger *Logger) Warn(args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warn(args...) entry.Warn(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -205,7 +206,7 @@ func (logger *Logger) Warn(args ...interface{}) {
} }
func (logger *Logger) Warning(args ...interface{}) { func (logger *Logger) Warning(args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warn(args...) entry.Warn(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -213,7 +214,7 @@ func (logger *Logger) Warning(args ...interface{}) {
} }
func (logger *Logger) Error(args ...interface{}) { func (logger *Logger) Error(args ...interface{}) {
if logger.Level >= ErrorLevel { if logger.level() >= ErrorLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Error(args...) entry.Error(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -221,7 +222,7 @@ func (logger *Logger) Error(args ...interface{}) {
} }
func (logger *Logger) Fatal(args ...interface{}) { func (logger *Logger) Fatal(args ...interface{}) {
if logger.Level >= FatalLevel { if logger.level() >= FatalLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Fatal(args...) entry.Fatal(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -230,7 +231,7 @@ func (logger *Logger) Fatal(args ...interface{}) {
} }
func (logger *Logger) Panic(args ...interface{}) { func (logger *Logger) Panic(args ...interface{}) {
if logger.Level >= PanicLevel { if logger.level() >= PanicLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Panic(args...) entry.Panic(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -238,7 +239,7 @@ func (logger *Logger) Panic(args ...interface{}) {
} }
func (logger *Logger) Debugln(args ...interface{}) { func (logger *Logger) Debugln(args ...interface{}) {
if logger.Level >= DebugLevel { if logger.level() >= DebugLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Debugln(args...) entry.Debugln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -246,7 +247,7 @@ func (logger *Logger) Debugln(args ...interface{}) {
} }
func (logger *Logger) Infoln(args ...interface{}) { func (logger *Logger) Infoln(args ...interface{}) {
if logger.Level >= InfoLevel { if logger.level() >= InfoLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Infoln(args...) entry.Infoln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -260,7 +261,7 @@ func (logger *Logger) Println(args ...interface{}) {
} }
func (logger *Logger) Warnln(args ...interface{}) { func (logger *Logger) Warnln(args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnln(args...) entry.Warnln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -268,7 +269,7 @@ func (logger *Logger) Warnln(args ...interface{}) {
} }
func (logger *Logger) Warningln(args ...interface{}) { func (logger *Logger) Warningln(args ...interface{}) {
if logger.Level >= WarnLevel { if logger.level() >= WarnLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnln(args...) entry.Warnln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -276,7 +277,7 @@ func (logger *Logger) Warningln(args ...interface{}) {
} }
func (logger *Logger) Errorln(args ...interface{}) { func (logger *Logger) Errorln(args ...interface{}) {
if logger.Level >= ErrorLevel { if logger.level() >= ErrorLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Errorln(args...) entry.Errorln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -284,7 +285,7 @@ func (logger *Logger) Errorln(args ...interface{}) {
} }
func (logger *Logger) Fatalln(args ...interface{}) { func (logger *Logger) Fatalln(args ...interface{}) {
if logger.Level >= FatalLevel { if logger.level() >= FatalLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Fatalln(args...) entry.Fatalln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -293,7 +294,7 @@ func (logger *Logger) Fatalln(args ...interface{}) {
} }
func (logger *Logger) Panicln(args ...interface{}) { func (logger *Logger) Panicln(args ...interface{}) {
if logger.Level >= PanicLevel { if logger.level() >= PanicLevel {
entry := logger.newEntry() entry := logger.newEntry()
entry.Panicln(args...) entry.Panicln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
@ -306,3 +307,11 @@ func (logger *Logger) Panicln(args ...interface{}) {
func (logger *Logger) SetNoLock() { func (logger *Logger) SetNoLock() {
logger.mu.Disable() logger.mu.Disable()
} }
func (logger *Logger) level() Level {
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
}
func (logger *Logger) setLevel(level Level) {
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
}

View File

@ -10,7 +10,7 @@ import (
type Fields map[string]interface{} type Fields map[string]interface{}
// Level type // Level type
type Level uint8 type Level uint32
// Convert the Level to a string. E.g. PanicLevel becomes "panic". // Convert the Level to a string. E.g. PanicLevel becomes "panic".
func (level Level) String() string { func (level Level) String() string {

View File

@ -2,7 +2,9 @@
package logrus package logrus
import "io"
// IsTerminal returns true if stderr's file descriptor is a terminal. // IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool { func IsTerminal(f io.Writer) bool {
return true return true
} }

View File

@ -9,14 +9,20 @@
package logrus package logrus
import ( import (
"io"
"os"
"syscall" "syscall"
"unsafe" "unsafe"
) )
// IsTerminal returns true if stderr's file descriptor is a terminal. // IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool { func IsTerminal(f io.Writer) bool {
fd := syscall.Stderr
var termios Termios var termios Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) switch v := f.(type) {
return err == 0 case *os.File:
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
default:
return false
}
} }

21
vendor/github.com/sirupsen/logrus/terminal_solaris.go generated vendored Normal file
View File

@ -0,0 +1,21 @@
// +build solaris,!appengine
package logrus
import (
"io"
"os"
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
_, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
return err == nil
default:
return false
}
}

82
vendor/github.com/sirupsen/logrus/terminal_windows.go generated vendored Normal file
View File

@ -0,0 +1,82 @@
// Based on ssh/terminal:
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows,!appengine
package logrus
import (
"bytes"
"errors"
"io"
"os"
"os/exec"
"strconv"
"strings"
"syscall"
"unsafe"
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
)
const (
enableProcessedOutput = 0x0001
enableWrapAtEolOutput = 0x0002
enableVirtualTerminalProcessing = 0x0004
)
func getVersion() (float64, error) {
stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
cmd := exec.Command("cmd", "ver")
cmd.Stdout = stdout
cmd.Stderr = stderr
err := cmd.Run()
if err != nil {
return -1, err
}
// The output should be like "Microsoft Windows [Version XX.X.XXXXXX]"
version := strings.Replace(stdout.String(), "\n", "", -1)
version = strings.Replace(version, "\r\n", "", -1)
x1 := strings.Index(version, "[Version")
if x1 == -1 || strings.Index(version, "]") == -1 {
return -1, errors.New("Can't determine Windows version")
}
return strconv.ParseFloat(version[x1+9:x1+13], 64)
}
func init() {
ver, err := getVersion()
if err != nil {
return
}
// Activate Virtual Processing for Windows CMD
// Info: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
if ver >= 10 {
handle := syscall.Handle(os.Stderr.Fd())
procSetConsoleMode.Call(uintptr(handle), enableProcessedOutput|enableWrapAtEolOutput|enableVirtualTerminalProcessing)
}
}
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
default:
return false
}
}

View File

@ -3,9 +3,9 @@ package logrus
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"runtime"
"sort" "sort"
"strings" "strings"
"sync"
"time" "time"
) )
@ -20,16 +20,10 @@ const (
var ( var (
baseTimestamp time.Time baseTimestamp time.Time
isTerminal bool
) )
func init() { func init() {
baseTimestamp = time.Now() baseTimestamp = time.Now()
isTerminal = IsTerminal()
}
func miniTS() int {
return int(time.Since(baseTimestamp) / time.Second)
} }
type TextFormatter struct { type TextFormatter struct {
@ -54,11 +48,32 @@ type TextFormatter struct {
// that log extremely frequently and don't use the JSON formatter this may not // that log extremely frequently and don't use the JSON formatter this may not
// be desired. // be desired.
DisableSorting bool DisableSorting bool
// QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool
// QuoteCharacter can be set to the override the default quoting character "
// with something else. For example: ', or `.
QuoteCharacter string
// Whether the logger's out is to a terminal
isTerminal bool
sync.Once
}
func (f *TextFormatter) init(entry *Entry) {
if len(f.QuoteCharacter) == 0 {
f.QuoteCharacter = "\""
}
if entry.Logger != nil {
f.isTerminal = IsTerminal(entry.Logger.Out)
}
} }
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var b *bytes.Buffer var b *bytes.Buffer
var keys []string = make([]string, 0, len(entry.Data)) keys := make([]string, 0, len(entry.Data))
for k := range entry.Data { for k := range entry.Data {
keys = append(keys, k) keys = append(keys, k)
} }
@ -74,8 +89,9 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
prefixFieldClashes(entry.Data) prefixFieldClashes(entry.Data)
isColorTerminal := isTerminal && (runtime.GOOS != "windows") f.Do(func() { f.init(entry) })
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
timestampFormat := f.TimestampFormat timestampFormat := f.TimestampFormat
if timestampFormat == "" { if timestampFormat == "" {
@ -115,8 +131,10 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
levelText := strings.ToUpper(entry.Level.String())[0:4] levelText := strings.ToUpper(entry.Level.String())[0:4]
if !f.FullTimestamp { if f.DisableTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message) fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
} else if !f.FullTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
} else { } else {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message) fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
} }
@ -127,7 +145,10 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
} }
} }
func needsQuoting(text string) bool { func (f *TextFormatter) needsQuoting(text string) bool {
if f.QuoteEmptyFields && len(text) == 0 {
return true
}
for _, ch := range text { for _, ch := range text {
if !((ch >= 'a' && ch <= 'z') || if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') || (ch >= 'A' && ch <= 'Z') ||
@ -150,17 +171,17 @@ func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interf
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
switch value := value.(type) { switch value := value.(type) {
case string: case string:
if !needsQuoting(value) { if !f.needsQuoting(value) {
b.WriteString(value) b.WriteString(value)
} else { } else {
fmt.Fprintf(b, "%q", value) fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
} }
case error: case error:
errmsg := value.Error() errmsg := value.Error()
if !needsQuoting(errmsg) { if !f.needsQuoting(errmsg) {
b.WriteString(errmsg) b.WriteString(errmsg)
} else { } else {
fmt.Fprintf(b, "%q", errmsg) fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
} }
default: default:
fmt.Fprint(b, value) fmt.Fprint(b, value)

View File

@ -11,39 +11,48 @@ func (logger *Logger) Writer() *io.PipeWriter {
} }
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
return NewEntry(logger).WriterLevel(level)
}
func (entry *Entry) Writer() *io.PipeWriter {
return entry.WriterLevel(InfoLevel)
}
func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
reader, writer := io.Pipe() reader, writer := io.Pipe()
var printFunc func(args ...interface{}) var printFunc func(args ...interface{})
switch level { switch level {
case DebugLevel: case DebugLevel:
printFunc = logger.Debug printFunc = entry.Debug
case InfoLevel: case InfoLevel:
printFunc = logger.Info printFunc = entry.Info
case WarnLevel: case WarnLevel:
printFunc = logger.Warn printFunc = entry.Warn
case ErrorLevel: case ErrorLevel:
printFunc = logger.Error printFunc = entry.Error
case FatalLevel: case FatalLevel:
printFunc = logger.Fatal printFunc = entry.Fatal
case PanicLevel: case PanicLevel:
printFunc = logger.Panic printFunc = entry.Panic
default: default:
printFunc = logger.Print printFunc = entry.Print
} }
go logger.writerScanner(reader, printFunc) go entry.writerScanner(reader, printFunc)
runtime.SetFinalizer(writer, writerFinalizer) runtime.SetFinalizer(writer, writerFinalizer)
return writer return writer
} }
func (logger *Logger) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
scanner := bufio.NewScanner(reader) scanner := bufio.NewScanner(reader)
for scanner.Scan() { for scanner.Scan() {
printFunc(scanner.Text()) printFunc(scanner.Text())
} }
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
logger.Errorf("Error while reading from Writer: %s", err) entry.Errorf("Error while reading from Writer: %s", err)
} }
reader.Close() reader.Close()
} }

View File

@ -10,7 +10,6 @@ import (
"time" "time"
"github.com/Microsoft/hcsshim" "github.com/Microsoft/hcsshim"
"github.com/Sirupsen/logrus"
"github.com/boltdb/bolt" "github.com/boltdb/bolt"
eventsapi "github.com/containerd/containerd/api/services/events/v1" eventsapi "github.com/containerd/containerd/api/services/events/v1"
containerdtypes "github.com/containerd/containerd/api/types" containerdtypes "github.com/containerd/containerd/api/types"
@ -24,6 +23,7 @@ import (
"github.com/containerd/containerd/windows/hcsshimopts" "github.com/containerd/containerd/windows/hcsshimopts"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
) )
const ( const (

View File

@ -10,7 +10,6 @@ import (
"time" "time"
"github.com/Microsoft/hcsshim" "github.com/Microsoft/hcsshim"
"github.com/Sirupsen/logrus"
eventsapi "github.com/containerd/containerd/api/services/events/v1" eventsapi "github.com/containerd/containerd/api/services/events/v1"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/events" "github.com/containerd/containerd/events"
@ -20,6 +19,7 @@ import (
"github.com/gogo/protobuf/types" "github.com/gogo/protobuf/types"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
) )
type task struct { type task struct {