Backend plugins: Updates due to changes in SDK (#22649)

Use v0.20.0 of SDK
This commit is contained in:
Marcus Efraimsson authored and GitHub committed 2020-03-10 12:59:03 +01:00
1 parent 805abdfa2a
commit c12245bbb3
141 files changed
+2482 -3121

No files matched your search

-83
View File
@@ -1,83 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/empty.proto
package empty
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// A generic empty message that you can re-use to avoid defining duplicated
// empty messages in your APIs. A typical example is to use it as the request
// or the response type of an API method. For instance:
//
// service Foo {
// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
// }
//
// The JSON representation for `Empty` is empty JSON object `{}`.
type Empty struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Empty) Reset() { *m = Empty{} }
func (m *Empty) String() string { return proto.CompactTextString(m) }
func (*Empty) ProtoMessage() {}
func (*Empty) Descriptor() ([]byte, []int) {
return fileDescriptor_900544acb223d5b8, []int{0}
}
func (*Empty) XXX_WellKnownType() string { return "Empty" }
func (m *Empty) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Empty.Unmarshal(m, b)
}
func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Empty.Marshal(b, m, deterministic)
}
func (m *Empty) XXX_Merge(src proto.Message) {
xxx_messageInfo_Empty.Merge(m, src)
}
func (m *Empty) XXX_Size() int {
return xxx_messageInfo_Empty.Size(m)
}
func (m *Empty) XXX_DiscardUnknown() {
xxx_messageInfo_Empty.DiscardUnknown(m)
}
var xxx_messageInfo_Empty proto.InternalMessageInfo
func init() {
proto.RegisterType((*Empty)(nil), "google.protobuf.Empty")
}
func init() { proto.RegisterFile("google/protobuf/empty.proto", fileDescriptor_900544acb223d5b8) }
var fileDescriptor_900544acb223d5b8 = []byte{
// 148 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4e, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcd, 0x2d, 0x28,
0xa9, 0xd4, 0x03, 0x73, 0x85, 0xf8, 0x21, 0x92, 0x7a, 0x30, 0x49, 0x25, 0x76, 0x2e, 0x56, 0x57,
0x90, 0xbc, 0x53, 0x19, 0x97, 0x70, 0x72, 0x7e, 0xae, 0x1e, 0x9a, 0xbc, 0x13, 0x17, 0x58, 0x36,
0x00, 0xc4, 0x0d, 0x60, 0x8c, 0x52, 0x4f, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf,
0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc, 0x4b, 0x47, 0x58, 0x53, 0x50, 0x52, 0x59, 0x90, 0x5a, 0x0c,
0xb1, 0xed, 0x07, 0x23, 0xe3, 0x22, 0x26, 0x66, 0xf7, 0x00, 0xa7, 0x55, 0x4c, 0x72, 0xee, 0x10,
0x13, 0x03, 0xa0, 0xea, 0xf4, 0xc2, 0x53, 0x73, 0x72, 0xbc, 0xf3, 0xf2, 0xcb, 0xf3, 0x42, 0x40,
0xea, 0x93, 0xd8, 0xc0, 0x06, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x64, 0xd4, 0xb3, 0xa6,
0xb7, 0x00, 0x00, 0x00,
}
-52
View File
@@ -1,52 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option go_package = "github.com/golang/protobuf/ptypes/empty";
option java_package = "com.google.protobuf";
option java_outer_classname = "EmptyProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
option cc_enable_arenas = true;
// A generic empty message that you can re-use to avoid defining duplicated
// empty messages in your APIs. A typical example is to use it as the request
// or the response type of an API method. For instance:
//
// service Foo {
// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
// }
//
// The JSON representation for `Empty` is empty JSON object `{}`.
message Empty {}
@@ -1,62 +0,0 @@
package plugin
import (
"context"
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
plugin "github.com/hashicorp/go-plugin"
"google.golang.org/grpc"
)
type CoreServer interface {
pluginv2.CoreServer
}
type CoreClient interface {
pluginv2.CoreClient
}
// CoreGRPCPlugin implements the GRPCPlugin interface from github.com/hashicorp/go-plugin.
type CoreGRPCPlugin struct {
plugin.NetRPCUnsupportedPlugin
plugin.GRPCPlugin
CoreServer CoreServer
}
func (p *CoreGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
pluginv2.RegisterCoreServer(s, &coreGRPCServer{
server: p.CoreServer,
})
return nil
}
func (p *CoreGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
return &coreGRPCClient{client: pluginv2.NewCoreClient(c)}, nil
}
type coreGRPCServer struct {
server CoreServer
}
func (s *coreGRPCServer) DataQuery(ctx context.Context, req *pluginv2.DataQueryRequest) (*pluginv2.DataQueryResponse, error) {
return s.server.DataQuery(ctx, req)
}
func (s *coreGRPCServer) CallResource(req *pluginv2.CallResource_Request, srv pluginv2.Core_CallResourceServer) error {
return s.server.CallResource(req, srv)
}
type coreGRPCClient struct {
client pluginv2.CoreClient
}
func (m *coreGRPCClient) DataQuery(ctx context.Context, req *pluginv2.DataQueryRequest, opts ...grpc.CallOption) (*pluginv2.DataQueryResponse, error) {
return m.client.DataQuery(ctx, req, opts...)
}
func (m *coreGRPCClient) CallResource(ctx context.Context, req *pluginv2.CallResource_Request, opts ...grpc.CallOption) (pluginv2.Core_CallResourceClient, error) {
return m.client.CallResource(ctx, req, opts...)
}
var _ CoreServer = &coreGRPCServer{}
var _ CoreClient = &coreGRPCClient{}
@@ -0,0 +1,54 @@
package plugin
import (
"context"
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
plugin "github.com/hashicorp/go-plugin"
"google.golang.org/grpc"
)
type DataServer interface {
pluginv2.DataServer
}
type DataClient interface {
pluginv2.DataClient
}
// DataGRPCPlugin implements the GRPCPlugin interface from github.com/hashicorp/go-plugin.
type DataGRPCPlugin struct {
plugin.NetRPCUnsupportedPlugin
plugin.GRPCPlugin
DataServer DataServer
}
func (p *DataGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
pluginv2.RegisterDataServer(s, &dataGRPCServer{
server: p.DataServer,
})
return nil
}
func (p *DataGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
return &dataGRPCClient{client: pluginv2.NewDataClient(c)}, nil
}
type dataGRPCServer struct {
server DataServer
}
func (s *dataGRPCServer) QueryData(ctx context.Context, req *pluginv2.QueryDataRequest) (*pluginv2.QueryDataResponse, error) {
return s.server.QueryData(ctx, req)
}
type dataGRPCClient struct {
client pluginv2.DataClient
}
func (m *dataGRPCClient) QueryData(ctx context.Context, req *pluginv2.QueryDataRequest, opts ...grpc.CallOption) (*pluginv2.QueryDataResponse, error) {
return m.client.QueryData(ctx, req, opts...)
}
var _ DataServer = &dataGRPCServer{}
var _ DataClient = &dataGRPCClient{}
@@ -12,6 +12,10 @@ type DiagnosticsServer interface {
pluginv2.DiagnosticsServer
}
type DiagnosticsClient interface {
pluginv2.DiagnosticsClient
}
// DiagnosticsGRPCPlugin implements the GRPCPlugin interface from github.com/hashicorp/go-plugin.
type DiagnosticsGRPCPlugin struct {
plugin.NetRPCUnsupportedPlugin
@@ -34,11 +38,11 @@ type diagnosticsGRPCServer struct {
server DiagnosticsServer
}
func (s *diagnosticsGRPCServer) CollectMetrics(ctx context.Context, req *pluginv2.CollectMetrics_Request) (*pluginv2.CollectMetrics_Response, error) {
func (s *diagnosticsGRPCServer) CollectMetrics(ctx context.Context, req *pluginv2.CollectMetricsRequest) (*pluginv2.CollectMetricsResponse, error) {
return s.server.CollectMetrics(ctx, req)
}
func (s *diagnosticsGRPCServer) CheckHealth(ctx context.Context, req *pluginv2.CheckHealth_Request) (*pluginv2.CheckHealth_Response, error) {
func (s *diagnosticsGRPCServer) CheckHealth(ctx context.Context, req *pluginv2.CheckHealthRequest) (*pluginv2.CheckHealthResponse, error) {
return s.server.CheckHealth(ctx, req)
}
@@ -46,13 +50,13 @@ type diagnosticsGRPCClient struct {
client pluginv2.DiagnosticsClient
}
func (s *diagnosticsGRPCClient) CollectMetrics(ctx context.Context, req *pluginv2.CollectMetrics_Request) (*pluginv2.CollectMetrics_Response, error) {
return s.client.CollectMetrics(ctx, req)
func (s *diagnosticsGRPCClient) CollectMetrics(ctx context.Context, req *pluginv2.CollectMetricsRequest, opts ...grpc.CallOption) (*pluginv2.CollectMetricsResponse, error) {
return s.client.CollectMetrics(ctx, req, opts...)
}
func (s *diagnosticsGRPCClient) CheckHealth(ctx context.Context, req *pluginv2.CheckHealth_Request) (*pluginv2.CheckHealth_Response, error) {
return s.client.CheckHealth(ctx, req)
func (s *diagnosticsGRPCClient) CheckHealth(ctx context.Context, req *pluginv2.CheckHealthRequest, opts ...grpc.CallOption) (*pluginv2.CheckHealthResponse, error) {
return s.client.CheckHealth(ctx, req, opts...)
}
var _ DiagnosticsServer = &diagnosticsGRPCServer{}
var _ DiagnosticsServer = &diagnosticsGRPCClient{}
var _ DiagnosticsClient = &diagnosticsGRPCClient{}
@@ -0,0 +1,54 @@
package plugin
import (
"context"
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
plugin "github.com/hashicorp/go-plugin"
"google.golang.org/grpc"
)
type ResourceServer interface {
pluginv2.ResourceServer
}
type ResourceClient interface {
pluginv2.ResourceClient
}
// ResourceGRPCPlugin implements the GRPCPlugin interface from github.com/hashicorp/go-plugin.
type ResourceGRPCPlugin struct {
plugin.NetRPCUnsupportedPlugin
plugin.GRPCPlugin
ResourceServer ResourceServer
}
func (p *ResourceGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
pluginv2.RegisterResourceServer(s, &resourceGRPCServer{
server: p.ResourceServer,
})
return nil
}
func (p *ResourceGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
return &resourceGRPCClient{client: pluginv2.NewResourceClient(c)}, nil
}
type resourceGRPCServer struct {
server ResourceServer
}
func (s *resourceGRPCServer) CallResource(req *pluginv2.CallResourceRequest, srv pluginv2.Resource_CallResourceServer) error {
return s.server.CallResource(req, srv)
}
type resourceGRPCClient struct {
client pluginv2.ResourceClient
}
func (m *resourceGRPCClient) CallResource(ctx context.Context, req *pluginv2.CallResourceRequest, opts ...grpc.CallOption) (pluginv2.Resource_CallResourceClient, error) {
return m.client.CallResource(ctx, req, opts...)
}
var _ ResourceServer = &resourceGRPCServer{}
var _ ResourceClient = &resourceGRPCClient{}
@@ -12,15 +12,15 @@ import (
)
type TransformServer interface {
TransformData(ctx context.Context, req *pluginv2.DataQueryRequest, callback TransformCallBack) (*pluginv2.DataQueryResponse, error)
TransformData(ctx context.Context, req *pluginv2.QueryDataRequest, callback TransformDataCallBack) (*pluginv2.QueryDataResponse, error)
}
type transformClient interface {
DataQuery(ctx context.Context, req *pluginv2.DataQueryRequest, callback TransformCallBack) (*pluginv2.DataQueryResponse, error)
type TransformClient interface {
TransformData(ctx context.Context, req *pluginv2.QueryDataRequest, callback TransformDataCallBack) (*pluginv2.QueryDataResponse, error)
}
type TransformCallBack interface {
DataQuery(ctx context.Context, req *pluginv2.DataQueryRequest) (*pluginv2.DataQueryResponse, error)
type TransformDataCallBack interface {
QueryData(ctx context.Context, req *pluginv2.QueryDataRequest) (*pluginv2.QueryDataResponse, error)
}
// TransformGRPCPlugin implements the GRPCPlugin interface from github.com/hashicorp/go-plugin.
@@ -47,7 +47,7 @@ type transformGRPCServer struct {
server TransformServer
}
func (t *transformGRPCServer) DataQuery(ctx context.Context, req *pluginv2.DataQueryRequest) (*pluginv2.DataQueryResponse, error) {
func (t *transformGRPCServer) TransformData(ctx context.Context, req *pluginv2.QueryDataRequest) (*pluginv2.QueryDataResponse, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, fmt.Errorf("transform request is missing metadata")
@@ -65,7 +65,7 @@ func (t *transformGRPCServer) DataQuery(ctx context.Context, req *pluginv2.DataQ
return nil, err
}
defer conn.Close()
api := &transformCallBackGrpcClient{pluginv2.NewTransformCallBackClient(conn)}
api := &transformDataCallBackGrpcClient{pluginv2.NewTransformDataCallBackClient(conn)}
return t.server.TransformData(ctx, req, api)
}
@@ -74,13 +74,13 @@ type transformGRPCClient struct {
client pluginv2.TransformClient
}
func (t *transformGRPCClient) DataQuery(ctx context.Context, req *pluginv2.DataQueryRequest, callBack TransformCallBack) (*pluginv2.DataQueryResponse, error) {
callBackServer := &transformCallBackGrpcServer{Impl: callBack}
func (t *transformGRPCClient) TransformData(ctx context.Context, req *pluginv2.QueryDataRequest, callBack TransformDataCallBack) (*pluginv2.QueryDataResponse, error) {
callBackServer := &transformDataCallBackGrpcServer{Impl: callBack}
var s *grpc.Server
serverFunc := func(opts []grpc.ServerOption) *grpc.Server {
s = grpc.NewServer(opts...)
pluginv2.RegisterTransformCallBackServer(s, callBackServer)
pluginv2.RegisterTransformDataCallBackServer(s, callBackServer)
return s
}
@@ -88,30 +88,30 @@ func (t *transformGRPCClient) DataQuery(ctx context.Context, req *pluginv2.DataQ
go t.broker.AcceptAndServe(brokerID, serverFunc)
ctx = metadata.AppendToOutgoingContext(ctx, "broker_requestId", strconv.FormatUint(uint64(brokerID), 10))
res, err := t.client.DataQuery(ctx, req)
res, err := t.client.TransformData(ctx, req)
s.Stop()
return res, err
}
// Callback
type transformCallBackGrpcServer struct {
Impl TransformCallBack
type transformDataCallBackGrpcServer struct {
Impl TransformDataCallBack
}
func (g *transformCallBackGrpcServer) DataQuery(ctx context.Context, req *pluginv2.DataQueryRequest) (*pluginv2.DataQueryResponse, error) {
return g.Impl.DataQuery(ctx, req)
func (g *transformDataCallBackGrpcServer) QueryData(ctx context.Context, req *pluginv2.QueryDataRequest) (*pluginv2.QueryDataResponse, error) {
return g.Impl.QueryData(ctx, req)
}
type transformCallBackGrpcClient struct {
client pluginv2.TransformCallBackClient
type transformDataCallBackGrpcClient struct {
client pluginv2.TransformDataCallBackClient
}
func (t *transformCallBackGrpcClient) DataQuery(ctx context.Context, req *pluginv2.DataQueryRequest) (*pluginv2.DataQueryResponse, error) {
return t.client.DataQuery(ctx, req)
func (t *transformDataCallBackGrpcClient) QueryData(ctx context.Context, req *pluginv2.QueryDataRequest) (*pluginv2.QueryDataResponse, error) {
return t.client.QueryData(ctx, req)
}
var _ pluginv2.TransformServer = &transformGRPCServer{}
var _ transformClient = &transformGRPCClient{}
var _ pluginv2.TransformServer = &transformCallBackGrpcServer{}
var _ pluginv2.TransformServer = &transformCallBackGrpcClient{}
var _ TransformClient = &transformGRPCClient{}
var _ TransformDataCallBack = &transformDataCallBackGrpcServer{}
var _ TransformDataCallBack = &transformDataCallBackGrpcClient{}
+11 -4
View File
@@ -8,7 +8,8 @@ import (
//ServeOpts options for serving plugins.
type ServeOpts struct {
DiagnosticsServer DiagnosticsServer
CoreServer CoreServer
ResourceServer ResourceServer
DataServer DataServer
TransformServer TransformServer
// GRPCServer factory method for creating GRPC server.
@@ -27,9 +28,15 @@ func Serve(opts ServeOpts) error {
}
}
if opts.CoreServer != nil {
pSet["backend"] = &CoreGRPCPlugin{
CoreServer: opts.CoreServer,
if opts.ResourceServer != nil {
pSet["resource"] = &ResourceGRPCPlugin{
ResourceServer: opts.ResourceServer,
}
}
if opts.DataServer != nil {
pSet["data"] = &DataGRPCPlugin{
DataServer: opts.DataServer,
}
}
File diff suppressed because it is too large. Load diff
-15
View File
@@ -128,21 +128,6 @@ stdLogger.Printf("[DEBUG] %+v", stdLogger)
... [DEBUG] my-app: &{mu:{state:0 sema:0} prefix: flag:0 out:0xc42000a0a0 buf:[]}
```
Alternatively, you may configure the system-wide logger:
```go
// log the standard logger from 'import "log"'
log.SetOutput(appLogger.Writer(&hclog.StandardLoggerOptions{InferLevels: true}))
log.SetPrefix("")
log.SetFlags(0)
log.Printf("[DEBUG] %d", 42)
```
```text
... [DEBUG] my-app: 42
```
Notice that if `appLogger` is initialized with the `INFO` log level _and_ you
specify `InferLevels: true`, you will not see any output here. You must change
`appLogger` to `DEBUG` to see output. See the docs for more information.
+5 -5
View File
@@ -8,16 +8,16 @@ var (
protect sync.Once
def Logger
// DefaultOptions is used to create the Default logger. These are read
// only when the Default logger is created, so set them as soon as the
// process starts.
// The options used to create the Default logger. These are
// read only when the Default logger is created, so set them
// as soon as the process starts.
DefaultOptions = &LoggerOptions{
Level: DefaultLevel,
Output: DefaultOutput,
}
)
// Default returns a globally held logger. This can be a good starting
// Return a logger that is held globally. This can be a good starting
// place, and then you can use .With() and .Name() to create sub-loggers
// to be used in more specific contexts.
func Default() Logger {
@@ -28,7 +28,7 @@ func Default() Logger {
return def
}
// L is a short alias for Default().
// A short alias for Default()
func L() Logger {
return Default()
}
-7
View File
@@ -1,7 +0,0 @@
module github.com/hashicorp/go-hclog
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2
)
-6
View File
@@ -1,6 +0,0 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -1,13 +1,12 @@
package hclog
import (
"bytes"
"bufio"
"encoding"
"encoding/json"
"fmt"
"io"
"log"
"reflect"
"os"
"runtime"
"sort"
"strconv"
@@ -17,41 +16,17 @@ import (
"time"
)
// TimeFormat to use for logging. This is a version of RFC3339 that contains
// contains millisecond precision
const TimeFormat = "2006-01-02T15:04:05.000Z0700"
var (
_levelToBracket = map[Level]string{
Debug: "[DEBUG]",
Trace: "[TRACE]",
Info: "[INFO] ",
Warn: "[WARN] ",
Info: "[INFO ]",
Warn: "[WARN ]",
Error: "[ERROR]",
}
)
// Make sure that intLogger is a Logger
var _ Logger = &intLogger{}
// intLogger is an internal logger implementation. Internal in that it is
// defined entirely by this package.
type intLogger struct {
json bool
caller bool
name string
timeFormat string
// This is a pointer so that it's shared by any derived loggers, since
// those derived loggers share the bufio.Writer as well.
mutex *sync.Mutex
writer *writer
level *int32
implied []interface{}
}
// New returns a configured logger.
// Given the options (nil for defaults), create a new Logger
func New(opts *LoggerOptions) Logger {
if opts == nil {
opts = &LoggerOptions{}
@@ -59,7 +34,7 @@ func New(opts *LoggerOptions) Logger {
output := opts.Output
if output == nil {
output = DefaultOutput
output = os.Stderr
}
level := opts.Level
@@ -67,49 +42,70 @@ func New(opts *LoggerOptions) Logger {
level = DefaultLevel
}
mutex := opts.Mutex
if mutex == nil {
mutex = new(sync.Mutex)
mtx := opts.Mutex
if mtx == nil {
mtx = new(sync.Mutex)
}
l := &intLogger{
ret := &intLogger{
m: mtx,
json: opts.JSONFormat,
caller: opts.IncludeLocation,
name: opts.Name,
timeFormat: TimeFormat,
mutex: mutex,
writer: newWriter(output),
w: bufio.NewWriter(output),
level: new(int32),
}
if opts.TimeFormat != "" {
l.timeFormat = opts.TimeFormat
ret.timeFormat = opts.TimeFormat
}
atomic.StoreInt32(l.level, int32(level))
return l
atomic.StoreInt32(ret.level, int32(level))
return ret
}
// The internal logger implementation. Internal in that it is defined entirely
// by this package.
type intLogger struct {
json bool
caller bool
name string
timeFormat string
// this is a pointer so that it's shared by any derived loggers, since
// those derived loggers share the bufio.Writer as well.
m *sync.Mutex
w *bufio.Writer
level *int32
implied []interface{}
}
// Make sure that intLogger is a Logger
var _ Logger = &intLogger{}
// The time format to use for logging. This is a version of RFC3339 that
// contains millisecond precision
const TimeFormat = "2006-01-02T15:04:05.000Z0700"
// Log a message and a set of key/value pairs if the given level is at
// or more severe that the threshold configured in the Logger.
func (l *intLogger) Log(level Level, msg string, args ...interface{}) {
if level < Level(atomic.LoadInt32(l.level)) {
func (z *intLogger) Log(level Level, msg string, args ...interface{}) {
if level < Level(atomic.LoadInt32(z.level)) {
return
}
t := time.Now()
l.mutex.Lock()
defer l.mutex.Unlock()
z.m.Lock()
defer z.m.Unlock()
if l.json {
l.logJSON(t, level, msg, args...)
if z.json {
z.logJson(t, level, msg, args...)
} else {
l.log(t, level, msg, args...)
z.log(t, level, msg, args...)
}
l.writer.Flush(level)
z.w.Flush()
}
// Cleanup a path by returning the last 2 segments of the path only.
@@ -125,8 +121,10 @@ func trimCallerPath(path string) string {
// and https://github.com/golang/go/issues/18151
//
// for discussion on the issue on Go side.
//
// Find the last separator.
//
idx := strings.LastIndexByte(path, '/')
if idx == -1 {
return path
@@ -142,37 +140,37 @@ func trimCallerPath(path string) string {
}
// Non-JSON logging format function
func (l *intLogger) log(t time.Time, level Level, msg string, args ...interface{}) {
l.writer.WriteString(t.Format(l.timeFormat))
l.writer.WriteByte(' ')
func (z *intLogger) log(t time.Time, level Level, msg string, args ...interface{}) {
z.w.WriteString(t.Format(z.timeFormat))
z.w.WriteByte(' ')
s, ok := _levelToBracket[level]
if ok {
l.writer.WriteString(s)
z.w.WriteString(s)
} else {
l.writer.WriteString("[?????]")
z.w.WriteString("[UNKN ]")
}
if l.caller {
if z.caller {
if _, file, line, ok := runtime.Caller(3); ok {
l.writer.WriteByte(' ')
l.writer.WriteString(trimCallerPath(file))
l.writer.WriteByte(':')
l.writer.WriteString(strconv.Itoa(line))
l.writer.WriteByte(':')
z.w.WriteByte(' ')
z.w.WriteString(trimCallerPath(file))
z.w.WriteByte(':')
z.w.WriteString(strconv.Itoa(line))
z.w.WriteByte(':')
}
}
l.writer.WriteByte(' ')
z.w.WriteByte(' ')
if l.name != "" {
l.writer.WriteString(l.name)
l.writer.WriteString(": ")
if z.name != "" {
z.w.WriteString(z.name)
z.w.WriteString(": ")
}
l.writer.WriteString(msg)
z.w.WriteString(msg)
args = append(l.implied, args...)
args = append(z.implied, args...)
var stacktrace CapturedStacktrace
@@ -187,14 +185,11 @@ func (l *intLogger) log(t time.Time, level Level, msg string, args ...interface{
}
}
l.writer.WriteByte(':')
z.w.WriteByte(':')
FOR:
for i := 0; i < len(args); i = i + 2 {
var (
val string
raw bool
)
var val string
switch st := args[i+1].(type) {
case string:
@@ -225,77 +220,32 @@ func (l *intLogger) log(t time.Time, level Level, msg string, args ...interface{
case Format:
val = fmt.Sprintf(st[0].(string), st[1:]...)
default:
v := reflect.ValueOf(st)
if v.Kind() == reflect.Slice {
val = l.renderSlice(v)
raw = true
} else {
val = fmt.Sprintf("%v", st)
}
val = fmt.Sprintf("%v", st)
}
l.writer.WriteByte(' ')
l.writer.WriteString(args[i].(string))
l.writer.WriteByte('=')
z.w.WriteByte(' ')
z.w.WriteString(args[i].(string))
z.w.WriteByte('=')
if !raw && strings.ContainsAny(val, " \t\n\r") {
l.writer.WriteByte('"')
l.writer.WriteString(val)
l.writer.WriteByte('"')
if strings.ContainsAny(val, " \t\n\r") {
z.w.WriteByte('"')
z.w.WriteString(val)
z.w.WriteByte('"')
} else {
l.writer.WriteString(val)
z.w.WriteString(val)
}
}
}
l.writer.WriteString("\n")
z.w.WriteString("\n")
if stacktrace != "" {
l.writer.WriteString(string(stacktrace))
z.w.WriteString(string(stacktrace))
}
}
func (l *intLogger) renderSlice(v reflect.Value) string {
var buf bytes.Buffer
buf.WriteRune('[')
for i := 0; i < v.Len(); i++ {
if i > 0 {
buf.WriteString(", ")
}
sv := v.Index(i)
var val string
switch sv.Kind() {
case reflect.String:
val = sv.String()
case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
val = strconv.FormatInt(sv.Int(), 10)
case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
val = strconv.FormatUint(sv.Uint(), 10)
default:
val = fmt.Sprintf("%v", sv.Interface())
}
if strings.ContainsAny(val, " \t\n\r") {
buf.WriteByte('"')
buf.WriteString(val)
buf.WriteByte('"')
} else {
buf.WriteString(val)
}
}
buf.WriteRune(']')
return buf.String()
}
// JSON logging function
func (l *intLogger) logJSON(t time.Time, level Level, msg string, args ...interface{}) {
func (z *intLogger) logJson(t time.Time, level Level, msg string, args ...interface{}) {
vals := map[string]interface{}{
"@message": msg,
"@timestamp": t.Format("2006-01-02T15:04:05.000000Z07:00"),
@@ -319,17 +269,17 @@ func (l *intLogger) logJSON(t time.Time, level Level, msg string, args ...interf
vals["@level"] = levelStr
if l.name != "" {
vals["@module"] = l.name
if z.name != "" {
vals["@module"] = z.name
}
if l.caller {
if z.caller {
if _, file, line, ok := runtime.Caller(3); ok {
vals["@caller"] = fmt.Sprintf("%s:%d", file, line)
}
}
args = append(l.implied, args...)
args = append(z.implied, args...)
if args != nil && len(args) > 0 {
if len(args)%2 != 0 {
@@ -367,80 +317,80 @@ func (l *intLogger) logJSON(t time.Time, level Level, msg string, args ...interf
}
}
err := json.NewEncoder(l.writer).Encode(vals)
err := json.NewEncoder(z.w).Encode(vals)
if err != nil {
panic(err)
}
}
// Emit the message and args at DEBUG level
func (l *intLogger) Debug(msg string, args ...interface{}) {
l.Log(Debug, msg, args...)
func (z *intLogger) Debug(msg string, args ...interface{}) {
z.Log(Debug, msg, args...)
}
// Emit the message and args at TRACE level
func (l *intLogger) Trace(msg string, args ...interface{}) {
l.Log(Trace, msg, args...)
func (z *intLogger) Trace(msg string, args ...interface{}) {
z.Log(Trace, msg, args...)
}
// Emit the message and args at INFO level
func (l *intLogger) Info(msg string, args ...interface{}) {
l.Log(Info, msg, args...)
func (z *intLogger) Info(msg string, args ...interface{}) {
z.Log(Info, msg, args...)
}
// Emit the message and args at WARN level
func (l *intLogger) Warn(msg string, args ...interface{}) {
l.Log(Warn, msg, args...)
func (z *intLogger) Warn(msg string, args ...interface{}) {
z.Log(Warn, msg, args...)
}
// Emit the message and args at ERROR level
func (l *intLogger) Error(msg string, args ...interface{}) {
l.Log(Error, msg, args...)
func (z *intLogger) Error(msg string, args ...interface{}) {
z.Log(Error, msg, args...)
}
// Indicate that the logger would emit TRACE level logs
func (l *intLogger) IsTrace() bool {
return Level(atomic.LoadInt32(l.level)) == Trace
func (z *intLogger) IsTrace() bool {
return Level(atomic.LoadInt32(z.level)) == Trace
}
// Indicate that the logger would emit DEBUG level logs
func (l *intLogger) IsDebug() bool {
return Level(atomic.LoadInt32(l.level)) <= Debug
func (z *intLogger) IsDebug() bool {
return Level(atomic.LoadInt32(z.level)) <= Debug
}
// Indicate that the logger would emit INFO level logs
func (l *intLogger) IsInfo() bool {
return Level(atomic.LoadInt32(l.level)) <= Info
func (z *intLogger) IsInfo() bool {
return Level(atomic.LoadInt32(z.level)) <= Info
}
// Indicate that the logger would emit WARN level logs
func (l *intLogger) IsWarn() bool {
return Level(atomic.LoadInt32(l.level)) <= Warn
func (z *intLogger) IsWarn() bool {
return Level(atomic.LoadInt32(z.level)) <= Warn
}
// Indicate that the logger would emit ERROR level logs
func (l *intLogger) IsError() bool {
return Level(atomic.LoadInt32(l.level)) <= Error
func (z *intLogger) IsError() bool {
return Level(atomic.LoadInt32(z.level)) <= Error
}
// Return a sub-Logger for which every emitted log message will contain
// the given key/value pairs. This is used to create a context specific
// Logger.
func (l *intLogger) With(args ...interface{}) Logger {
func (z *intLogger) With(args ...interface{}) Logger {
if len(args)%2 != 0 {
panic("With() call requires paired arguments")
}
sl := *l
var nz intLogger = *z
result := make(map[string]interface{}, len(l.implied)+len(args))
keys := make([]string, 0, len(l.implied)+len(args))
result := make(map[string]interface{}, len(z.implied)+len(args))
keys := make([]string, 0, len(z.implied)+len(args))
// Read existing args, store map and key for consistent sorting
for i := 0; i < len(l.implied); i += 2 {
key := l.implied[i].(string)
for i := 0; i < len(z.implied); i += 2 {
key := z.implied[i].(string)
keys = append(keys, key)
result[key] = l.implied[i+1]
result[key] = z.implied[i+1]
}
// Read new args, store map and key for consistent sorting
for i := 0; i < len(args); i += 2 {
@@ -455,57 +405,53 @@ func (l *intLogger) With(args ...interface{}) Logger {
// Sort keys to be consistent
sort.Strings(keys)
sl.implied = make([]interface{}, 0, len(l.implied)+len(args))
nz.implied = make([]interface{}, 0, len(z.implied)+len(args))
for _, k := range keys {
sl.implied = append(sl.implied, k)
sl.implied = append(sl.implied, result[k])
nz.implied = append(nz.implied, k)
nz.implied = append(nz.implied, result[k])
}
return &sl
return &nz
}
// Create a new sub-Logger that a name decending from the current name.
// This is used to create a subsystem specific Logger.
func (l *intLogger) Named(name string) Logger {
sl := *l
func (z *intLogger) Named(name string) Logger {
var nz intLogger = *z
if sl.name != "" {
sl.name = sl.name + "." + name
if nz.name != "" {
nz.name = nz.name + "." + name
} else {
sl.name = name
nz.name = name
}
return &sl
return &nz
}
// Create a new sub-Logger with an explicit name. This ignores the current
// name. This is used to create a standalone logger that doesn't fall
// within the normal hierarchy.
func (l *intLogger) ResetNamed(name string) Logger {
sl := *l
func (z *intLogger) ResetNamed(name string) Logger {
var nz intLogger = *z
sl.name = name
nz.name = name
return &sl
return &nz
}
// Update the logging level on-the-fly. This will affect all subloggers as
// well.
func (l *intLogger) SetLevel(level Level) {
atomic.StoreInt32(l.level, int32(level))
func (z *intLogger) SetLevel(level Level) {
atomic.StoreInt32(z.level, int32(level))
}
// Create a *log.Logger that will send it's data through this Logger. This
// allows packages that expect to be using the standard library log to actually
// use this logger.
func (l *intLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger {
func (z *intLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger {
if opts == nil {
opts = &StandardLoggerOptions{}
}
return log.New(l.StandardWriter(opts), "", 0)
}
func (l *intLogger) StandardWriter(opts *StandardLoggerOptions) io.Writer {
return &stdlogAdapter{l, opts.InferLevels}
return log.New(&stdlogAdapter{z, opts.InferLevels}, "", 0)
}
@@ -9,42 +9,38 @@ import (
)
var (
//DefaultOutput is used as the default log output.
DefaultOutput io.Writer = os.Stderr
// DefaultLevel is used as the default log level.
DefaultLevel = Info
DefaultOutput = os.Stderr
DefaultLevel = Info
)
// Level represents a log level.
type Level int32
const (
// NoLevel is a special level used to indicate that no level has been
// This is a special level used to indicate that no level has been
// set and allow for a default to be used.
NoLevel Level = 0
// Trace is the most verbose level. Intended to be used for the tracing
// of actions in code, such as function enters/exits, etc.
// The most verbose level. Intended to be used for the tracing of actions
// in code, such as function enters/exits, etc.
Trace Level = 1
// Debug information for programmer lowlevel analysis.
// For programmer lowlevel analysis.
Debug Level = 2
// Info information about steady state operations.
// For information about steady state operations.
Info Level = 3
// Warn information about rare but handled events.
// For information about rare but handled events.
Warn Level = 4
// Error information about unrecoverable events.
// For information about unrecoverable events.
Error Level = 5
)
// Format is a simple convience type for when formatting is required. When
// processing a value of this type, the logger automatically treats the first
// argument as a Printf formatting string and passes the rest as the values
// to be formatted. For example: L.Info(Fmt{"%d beans/day", beans}).
// When processing a value of this type, the logger automatically treats the first
// argument as a Printf formatting string and passes the rest as the values to be
// formatted. For example: L.Info(Fmt{"%d beans/day", beans}). This is a simple
// convience type for when formatting is required.
type Format []interface{}
// Fmt returns a Format type. This is a convience function for creating a Format
@@ -57,7 +53,7 @@ func Fmt(str string, args ...interface{}) Format {
// the level string is invalid. This facilitates setting the log level via
// config or environment variable by name in a predictable way.
func LevelFromString(levelStr string) Level {
// We don't care about case. Accept both "INFO" and "info".
// We don't care about case. Accept "INFO" or "info"
levelStr = strings.ToLower(strings.TrimSpace(levelStr))
switch levelStr {
case "trace":
@@ -75,7 +71,7 @@ func LevelFromString(levelStr string) Level {
}
}
// Logger describes the interface that must be implemeted by all loggers.
// The main Logger interface. All code should code against this interface only.
type Logger interface {
// Args are alternating key, val pairs
// keys must be strings
@@ -131,12 +127,8 @@ type Logger interface {
// Return a value that conforms to the stdlib log.Logger interface
StandardLogger(opts *StandardLoggerOptions) *log.Logger
// Return a value that conforms to io.Writer, which can be passed into log.SetOutput()
StandardWriter(opts *StandardLoggerOptions) io.Writer
}
// StandardLoggerOptions can be used to configure a new standard logger.
type StandardLoggerOptions struct {
// Indicate that some minimal parsing should be done on strings to try
// and detect their level and re-emit them.
@@ -145,7 +137,6 @@ type StandardLoggerOptions struct {
InferLevels bool
}
// LoggerOptions can be used to configure a new logger.
type LoggerOptions struct {
// Name of the subsystem to prefix logs with
Name string
@@ -153,7 +144,7 @@ type LoggerOptions struct {
// The threshold for the logger. Anything less severe is supressed
Level Level
// Where to write the logs to. Defaults to os.Stderr if nil
// Where to write the logs to. Defaults to os.Stdout if nil
Output io.Writer
// An optional mutex pointer in case Output is shared
+1 -6
View File
@@ -1,7 +1,6 @@
package hclog
import (
"io"
"io/ioutil"
"log"
)
@@ -44,9 +43,5 @@ func (l *nullLogger) ResetNamed(name string) Logger { return l }
func (l *nullLogger) SetLevel(level Level) {}
func (l *nullLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger {
return log.New(l.StandardWriter(opts), "", log.LstdFlags)
}
func (l *nullLogger) StandardWriter(opts *StandardLoggerOptions) io.Writer {
return ioutil.Discard
return log.New(ioutil.Discard, "", log.LstdFlags)
}
+4 -5
View File
@@ -40,13 +40,12 @@ var (
}
)
// CapturedStacktrace represents a stacktrace captured by a previous call
// to log.Stacktrace. If passed to a logging function, the stacktrace
// will be appended.
// A stacktrace gathered by a previous call to log.Stacktrace. If passed
// to a logging function, the stacktrace will be appended.
type CapturedStacktrace string
// Stacktrace captures a stacktrace of the current goroutine and returns
// it to be passed to a logging function.
// Gather a stacktrace of the current goroutine and return it to be passed
// to a logging function.
func Stacktrace() CapturedStacktrace {
return CapturedStacktrace(takeStacktrace())
}
+10 -10
View File
@@ -9,12 +9,12 @@ import (
// and back into our Logger. This is basically the only way to
// build upon *log.Logger.
type stdlogAdapter struct {
log Logger
hl Logger
inferLevels bool
}
// Take the data, infer the levels if configured, and send it through
// a regular Logger.
// a regular Logger
func (s *stdlogAdapter) Write(data []byte) (int, error) {
str := string(bytes.TrimRight(data, " \t\n"))
@@ -22,26 +22,26 @@ func (s *stdlogAdapter) Write(data []byte) (int, error) {
level, str := s.pickLevel(str)
switch level {
case Trace:
s.log.Trace(str)
s.hl.Trace(str)
case Debug:
s.log.Debug(str)
s.hl.Debug(str)
case Info:
s.log.Info(str)
s.hl.Info(str)
case Warn:
s.log.Warn(str)
s.hl.Warn(str)
case Error:
s.log.Error(str)
s.hl.Error(str)
default:
s.log.Info(str)
s.hl.Info(str)
}
} else {
s.log.Info(str)
s.hl.Info(str)
}
return len(data), nil
}
// Detect, based on conventions, what log level this is.
// Detect, based on conventions, what log level this is
func (s *stdlogAdapter) pickLevel(str string) (Level, string) {
switch {
case strings.HasPrefix(str, "[DEBUG]"):
-74
View File
@@ -1,74 +0,0 @@
package hclog
import (
"bytes"
"io"
)
type writer struct {
b bytes.Buffer
w io.Writer
}
func newWriter(w io.Writer) *writer {
return &writer{w: w}
}
func (w *writer) Flush(level Level) (err error) {
if lw, ok := w.w.(LevelWriter); ok {
_, err = lw.LevelWrite(level, w.b.Bytes())
} else {
_, err = w.w.Write(w.b.Bytes())
}
w.b.Reset()
return err
}
func (w *writer) Write(p []byte) (int, error) {
return w.b.Write(p)
}
func (w *writer) WriteByte(c byte) error {
return w.b.WriteByte(c)
}
func (w *writer) WriteString(s string) (int, error) {
return w.b.WriteString(s)
}
// LevelWriter is the interface that wraps the LevelWrite method.
type LevelWriter interface {
LevelWrite(level Level, p []byte) (n int, err error)
}
// LeveledWriter writes all log messages to the standard writer,
// except for log levels that are defined in the overrides map.
type LeveledWriter struct {
standard io.Writer
overrides map[Level]io.Writer
}
// NewLeveledWriter returns an initialized LeveledWriter.
//
// standard will be used as the default writer for all log levels,
// except for log levels that are defined in the overrides map.
func NewLeveledWriter(standard io.Writer, overrides map[Level]io.Writer) *LeveledWriter {
return &LeveledWriter{
standard: standard,
overrides: overrides,
}
}
// Write implements io.Writer.
func (lw *LeveledWriter) Write(p []byte) (int, error) {
return lw.standard.Write(p)
}
// LevelWrite implements LevelWriter.
func (lw *LeveledWriter) LevelWrite(level Level, p []byte) (int, error) {
w, ok := lw.overrides[level]
if !ok {
w = lw.standard
}
return w.Write(p)
}
+2 -2
View File
@@ -1,8 +1,8 @@
# go-colorable
[![Godoc Reference](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable)
[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable)
[![Coverage Status](https://coveralls.io/repos/github/mattn/go-colorable/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-colorable?branch=master)
[![Codecov](https://codecov.io/gh/mattn/go-colorable/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-colorable)
[![GoDoc](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable)
[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable)
Colorable writer for windows.
+8
View File
@@ -27,3 +27,11 @@ func NewColorableStdout() io.Writer {
func NewColorableStderr() io.Writer {
return os.Stderr
}
// EnableColorsStdout enable colors if possible.
func EnableColorsStdout(enabled *bool) func() {
if enabled != nil {
*enabled = true
}
return func() {}
}
+8
View File
@@ -28,3 +28,11 @@ func NewColorableStdout() io.Writer {
func NewColorableStderr() io.Writer {
return os.Stderr
}
// EnableColorsStdout enable colors if possible.
func EnableColorsStdout(enabled *bool) func() {
if enabled != nil {
*enabled = true
}
return func() {}
}
+28
View File
@@ -27,6 +27,8 @@ const (
backgroundRed = 0x40
backgroundIntensity = 0x80
backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
cENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4
)
const (
@@ -78,6 +80,8 @@ var (
procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer")
)
@@ -98,6 +102,10 @@ func NewColorable(file *os.File) io.Writer {
}
if isatty.IsTerminal(file.Fd()) {
var mode uint32
if r, _, _ := procGetConsoleMode.Call(file.Fd(), uintptr(unsafe.Pointer(&mode))); r != 0 && mode&cENABLE_VIRTUAL_TERMINAL_PROCESSING != 0 {
return file
}
var csbi consoleScreenBufferInfo
handle := syscall.Handle(file.Fd())
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
@@ -1003,3 +1011,23 @@ func n256setup() {
n256backAttr[i] = c.backgroundAttr()
}
}
// EnableColorsStdout enable colors if possible.
func EnableColorsStdout(enabled *bool) func() {
var mode uint32
h := os.Stdout.Fd()
if r, _, _ := procGetConsoleMode.Call(h, uintptr(unsafe.Pointer(&mode))); r != 0 {
if r, _, _ = procSetConsoleMode.Call(h, uintptr(mode|cENABLE_VIRTUAL_TERMINAL_PROCESSING)); r != 0 {
if enabled != nil {
*enabled = true
}
return func() {
procSetConsoleMode.Call(h, uintptr(mode))
}
}
}
if enabled != nil {
*enabled = true
}
return func() {}
}
+6 -1
View File
@@ -1,3 +1,8 @@
module github.com/mattn/go-colorable
require github.com/mattn/go-isatty v0.0.8
require (
github.com/mattn/go-isatty v0.0.12
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae // indirect
)
go 1.13
+5 -4
View File
@@ -1,4 +1,5 @@
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -e
echo "" > coverage.txt
for d in $(go list ./... | grep -v vendor); do
go test -race -coverprofile=profile.out -covermode=atomic "$d"
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
fi
done
+1 -1
View File
@@ -1,7 +1,7 @@
# go-isatty
[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty)
[![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty)
[![Codecov](https://codecov.io/gh/mattn/go-isatty/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-isatty)
[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master)
[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty)
+2 -2
View File
@@ -1,5 +1,5 @@
module github.com/mattn/go-isatty
require golang.org/x/sys v0.0.0-20191008105621-543471e840be
go 1.12
go 1.14
require golang.org/x/sys v0.0.0-20200116001909-b77594299b42
+2 -4
View File
@@ -1,4 +1,2 @@
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -e
echo "" > coverage.txt
for d in $(go list ./... | grep -v vendor); do
go test -race -coverprofile=profile.out -covermode=atomic "$d"
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
fi
done
-23
View File
@@ -1,23 +0,0 @@
// +build android
package isatty
import (
"syscall"
"unsafe"
)
const ioctlReadTermios = syscall.TCGETS
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}
+3 -9
View File
@@ -3,18 +3,12 @@
package isatty
import (
"syscall"
"unsafe"
)
const ioctlReadTermios = syscall.TIOCGETA
import "golang.org/x/sys/unix"
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
_, err := unix.IoctlGetTermios(int(fd), unix.TIOCGETA)
return err == nil
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
+1 -1
View File
@@ -8,7 +8,7 @@ import (
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
path, err := syscall.Fd2path(fd)
path, err := syscall.Fd2path(int(fd))
if err != nil {
return false
}
-1
View File
@@ -1,6 +1,5 @@
// +build linux aix
// +build !appengine
// +build !android
package isatty
+8
View File
@@ -0,0 +1,8 @@
{
"extends": [
"config:base"
],
"postUpdateOptions": [
"gomodTidy"
]
}