diff --git a/cmd/dex/config.go b/cmd/dex/config.go index dc3715b8..a2a653a7 100644 --- a/cmd/dex/config.go +++ b/cmd/dex/config.go @@ -8,6 +8,7 @@ import ( "golang.org/x/crypto/bcrypt" + "github.com/Sirupsen/logrus" "github.com/coreos/dex/connector" "github.com/coreos/dex/connector/github" "github.com/coreos/dex/connector/ldap" @@ -29,6 +30,7 @@ type Config struct { OAuth2 OAuth2 `json:"oauth2"` GRPC GRPC `json:"grpc"` Expiry Expiry `json:"expiry"` + Logger Logger `json:"logger"` Frontend server.WebConfig `json:"frontend"` @@ -119,7 +121,7 @@ type Storage struct { // StorageConfig is a configuration that can create a storage. type StorageConfig interface { - Open() (storage.Storage, error) + Open(logrus.FieldLogger) (storage.Storage, error) } var storages = map[string]func() StorageConfig{ @@ -170,7 +172,7 @@ type Connector struct { // ConnectorConfig is a configuration that can open a connector. type ConnectorConfig interface { - Open() (connector.Connector, error) + Open(logrus.FieldLogger) (connector.Connector, error) } var connectors = map[string]func() ConnectorConfig{ @@ -223,3 +225,12 @@ type Expiry struct { // IdTokens defines the duration of time for which the IdTokens will be valid. IDTokens string `json:"idTokens"` } + +// Logger holds configuration required to customize logging for dex. +type Logger struct { + // Level sets logging level severity. + Level string `json:"level"` + + // Format specifies the format to be used for logging. + Format string `json:"format"` +} diff --git a/cmd/dex/config_test.go b/cmd/dex/config_test.go index f0126f82..004fec00 100644 --- a/cmd/dex/config_test.go +++ b/cmd/dex/config_test.go @@ -59,6 +59,10 @@ staticPasswords: expiry: signingKeys: "6h" idTokens: "24h" + +logger: + level: "debug" + format: "json" `) want := Config{ @@ -120,6 +124,10 @@ expiry: SigningKeys: "6h", IDTokens: "24h", }, + Logger: Logger{ + Level: "debug", + Format: "json", + }, } var c Config diff --git a/cmd/dex/serve.go b/cmd/dex/serve.go index c9baa9d3..b47ea9ef 100644 --- a/cmd/dex/serve.go +++ b/cmd/dex/serve.go @@ -9,8 +9,11 @@ import ( "log" "net" "net/http" + "os" + "strings" "time" + "github.com/Sirupsen/logrus" "github.com/ghodss/yaml" "github.com/spf13/cobra" "golang.org/x/net/context" @@ -111,6 +114,8 @@ func serve(cmd *cobra.Command, args []string) error { } } + logger, _ := newLogger(c.Logger.Level, c.Logger.Format) + connectors := make([]server.Connector, len(c.Connectors)) for i, conn := range c.Connectors { if conn.ID == "" { @@ -119,7 +124,8 @@ func serve(cmd *cobra.Command, args []string) error { if conn.Config == nil { return fmt.Errorf("no config field for connector %q", conn.ID) } - c, err := conn.Config.Open() + connectorLogger := logger.WithField("connector", conn.Name) + c, err := conn.Config.Open(connectorLogger) if err != nil { return fmt.Errorf("open %s: %v", conn.ID, err) } @@ -130,7 +136,7 @@ func serve(cmd *cobra.Command, args []string) error { } } - s, err := c.Storage.Config.Open() + s, err := c.Storage.Config.Open(logger) if err != nil { return fmt.Errorf("initializing storage: %v", err) } @@ -153,6 +159,7 @@ func serve(cmd *cobra.Command, args []string) error { Storage: s, Web: c.Frontend, EnablePasswordDB: c.EnablePasswordDB, + Logger: logger, } if c.Expiry.SigningKeys != "" { signingKeys, err := time.ParseDuration(c.Expiry.SigningKeys) @@ -203,3 +210,33 @@ func serve(cmd *cobra.Command, args []string) error { return <-errc } + +func newLogger(level string, format string) (logrus.FieldLogger, error) { + var logLevel logrus.Level + switch strings.ToLower(level) { + case "debug": + logLevel = logrus.DebugLevel + case "", "info": + logLevel = logrus.InfoLevel + case "error": + logLevel = logrus.ErrorLevel + default: + return nil, fmt.Errorf("unsupported logLevel: %s", level) + } + + var formatter logrus.Formatter + switch strings.ToLower(format) { + case "", "text": + formatter = &logrus.TextFormatter{DisableColors: true} + case "json": + formatter = &logrus.JSONFormatter{} + default: + return nil, fmt.Errorf("unsupported logger format: %s", format) + } + + return &logrus.Logger{ + Out: os.Stderr, + Formatter: formatter, + Level: logLevel, + }, nil +} diff --git a/connector/github/github.go b/connector/github/github.go index 149883aa..4ed43852 100644 --- a/connector/github/github.go +++ b/connector/github/github.go @@ -13,6 +13,7 @@ import ( "golang.org/x/oauth2" "golang.org/x/oauth2/github" + "github.com/Sirupsen/logrus" "github.com/coreos/dex/connector" ) @@ -31,12 +32,13 @@ type Config struct { } // Open returns a strategy for logging in through GitHub. -func (c *Config) Open() (connector.Connector, error) { +func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) { return &githubConnector{ redirectURI: c.RedirectURI, org: c.Org, clientID: c.ClientID, clientSecret: c.ClientSecret, + logger: logger, }, nil } @@ -55,6 +57,7 @@ type githubConnector struct { org string clientID string clientSecret string + logger logrus.FieldLogger } func (c *githubConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config { diff --git a/connector/ldap/ldap.go b/connector/ldap/ldap.go index d39175c3..1af9aab1 100644 --- a/connector/ldap/ldap.go +++ b/connector/ldap/ldap.go @@ -13,6 +13,7 @@ import ( "golang.org/x/net/context" "gopkg.in/ldap.v2" + "github.com/Sirupsen/logrus" "github.com/coreos/dex/connector" ) @@ -135,8 +136,8 @@ func parseScope(s string) (int, bool) { } // Open returns an authentication strategy using LDAP. -func (c *Config) Open() (connector.Connector, error) { - conn, err := c.OpenConnector() +func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) { + conn, err := c.OpenConnector(logger) if err != nil { return nil, err } @@ -149,7 +150,7 @@ type refreshData struct { } // OpenConnector is the same as Open but returns a type with all implemented connector interfaces. -func (c *Config) OpenConnector() (interface { +func (c *Config) OpenConnector(logger logrus.FieldLogger) (interface { connector.Connector connector.PasswordConnector connector.RefreshConnector @@ -206,7 +207,7 @@ func (c *Config) OpenConnector() (interface { if !ok { return nil, fmt.Errorf("userSearch.Scope unknown value %q", c.GroupSearch.Scope) } - return &ldapConnector{*c, userSearchScope, groupSearchScope, tlsConfig}, nil + return &ldapConnector{*c, userSearchScope, groupSearchScope, tlsConfig, logger}, nil } type ldapConnector struct { @@ -216,6 +217,8 @@ type ldapConnector struct { groupSearchScope int tlsConfig *tls.Config + + logger logrus.FieldLogger } var ( diff --git a/connector/mock/connectortest.go b/connector/mock/connectortest.go index 167b0fb2..b754705b 100644 --- a/connector/mock/connectortest.go +++ b/connector/mock/connectortest.go @@ -9,12 +9,13 @@ import ( "golang.org/x/net/context" + "github.com/Sirupsen/logrus" "github.com/coreos/dex/connector" ) // NewCallbackConnector returns a mock connector which requires no user interaction. It always returns // the same (fake) identity. -func NewCallbackConnector() connector.Connector { +func NewCallbackConnector(logger logrus.FieldLogger) connector.Connector { return &Callback{ Identity: connector.Identity{ UserID: "0-385-28089-0", @@ -24,6 +25,7 @@ func NewCallbackConnector() connector.Connector { Groups: []string{"authors"}, ConnectorData: connectorData, }, + Logger: logger, } } @@ -37,6 +39,7 @@ var ( type Callback struct { // The returned identity. Identity connector.Identity + Logger logrus.FieldLogger } // LoginURL returns the URL to redirect the user to login with. @@ -67,8 +70,8 @@ func (m *Callback) Refresh(ctx context.Context, s connector.Scopes, identity con type CallbackConfig struct{} // Open returns an authentication strategy which requires no user interaction. -func (c *CallbackConfig) Open() (connector.Connector, error) { - return NewCallbackConnector(), nil +func (c *CallbackConfig) Open(logger logrus.FieldLogger) (connector.Connector, error) { + return NewCallbackConnector(logger), nil } // PasswordConfig holds the configuration for a mock connector which prompts for the supplied @@ -79,19 +82,20 @@ type PasswordConfig struct { } // Open returns an authentication strategy which prompts for a predefined username and password. -func (c *PasswordConfig) Open() (connector.Connector, error) { +func (c *PasswordConfig) Open(logger logrus.FieldLogger) (connector.Connector, error) { if c.Username == "" { return nil, errors.New("no username supplied") } if c.Password == "" { return nil, errors.New("no password supplied") } - return &passwordConnector{c.Username, c.Password}, nil + return &passwordConnector{c.Username, c.Password, logger}, nil } type passwordConnector struct { username string password string + logger logrus.FieldLogger } func (p passwordConnector) Close() error { return nil } diff --git a/connector/oidc/oidc.go b/connector/oidc/oidc.go index 6a71d017..6a8b6f98 100644 --- a/connector/oidc/oidc.go +++ b/connector/oidc/oidc.go @@ -6,6 +6,7 @@ import ( "fmt" "net/http" + "github.com/Sirupsen/logrus" "github.com/coreos/go-oidc" "golang.org/x/net/context" "golang.org/x/oauth2" @@ -25,7 +26,7 @@ type Config struct { // Open returns a connector which can be used to login users through an upstream // OpenID Connect provider. -func (c *Config) Open() (conn connector.Connector, err error) { +func (c *Config) Open(logger logrus.FieldLogger) (conn connector.Connector, err error) { ctx, cancel := context.WithCancel(context.Background()) provider, err := oidc.NewProvider(ctx, c.Issuer) @@ -55,6 +56,7 @@ func (c *Config) Open() (conn connector.Connector, err error) { oidc.VerifyExpiry(), oidc.VerifyAudience(clientID), ), + logger: logger, }, nil } @@ -68,6 +70,7 @@ type oidcConnector struct { verifier *oidc.IDTokenVerifier ctx context.Context cancel context.CancelFunc + logger logrus.FieldLogger } func (c *oidcConnector) Close() error { diff --git a/server/api_test.go b/server/api_test.go index f6eb7a4d..9f325cba 100644 --- a/server/api_test.go +++ b/server/api_test.go @@ -2,15 +2,23 @@ package server import ( "context" + "os" "testing" + "github.com/Sirupsen/logrus" "github.com/coreos/dex/api" "github.com/coreos/dex/storage/memory" ) // Attempts to create, update and delete a test Password func TestPassword(t *testing.T) { - s := memory.New() + logger := &logrus.Logger{ + Out: os.Stderr, + Formatter: &logrus.TextFormatter{DisableColors: true}, + Level: logrus.DebugLevel, + } + + s := memory.New(logger) serv := NewAPI(s) ctx := context.Background() diff --git a/server/server.go b/server/server.go index 91d119e9..1a87cb9c 100644 --- a/server/server.go +++ b/server/server.go @@ -13,6 +13,7 @@ import ( "golang.org/x/crypto/bcrypt" "golang.org/x/net/context" + "github.com/Sirupsen/logrus" "github.com/gorilla/mux" "github.com/coreos/dex/connector" @@ -57,6 +58,8 @@ type Config struct { EnablePasswordDB bool Web WebConfig + + Logger logrus.FieldLogger } // WebConfig holds the server's frontend templates and asset configuration. @@ -112,6 +115,8 @@ type Server struct { now func() time.Time idTokensValidFor time.Duration + + logger logrus.FieldLogger } // NewServer constructs a server from the provided config. @@ -182,6 +187,7 @@ func newServer(ctx context.Context, c Config, rotationStrategy rotationStrategy) skipApproval: c.SkipApprovalScreen, now: now, templates: tmpls, + logger: c.Logger, } for _, conn := range c.Connectors { diff --git a/server/server_test.go b/server/server_test.go index 3ab41940..4c9621c9 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -20,6 +20,7 @@ import ( "testing" "time" + "github.com/Sirupsen/logrus" oidc "github.com/coreos/go-oidc" "github.com/kylelemons/godebug/pretty" "golang.org/x/crypto/bcrypt" @@ -72,19 +73,26 @@ FDWV28nTP9sqbtsmU8Tem2jzMvZ7C/Q0AuDoKELFUpux8shm8wfIhyaPnXUGZoAZ Np4vUwMSYV5mopESLWOg3loBxKyLGFtgGKVCjGiQvy6zISQ4fQo= -----END RSA PRIVATE KEY-----`) +var logger = &logrus.Logger{ + Out: os.Stderr, + Formatter: &logrus.TextFormatter{DisableColors: true}, + Level: logrus.DebugLevel, +} + func newTestServer(ctx context.Context, t *testing.T, updateConfig func(c *Config)) (*httptest.Server, *Server) { var server *Server s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server.ServeHTTP(w, r) })) + config := Config{ Issuer: s.URL, - Storage: memory.New(), + Storage: memory.New(logger), Connectors: []Connector{ { ID: "mock", DisplayName: "Mock", - Connector: mock.NewCallbackConnector(), + Connector: mock.NewCallbackConnector(logger), }, }, Web: WebConfig{ @@ -367,12 +375,17 @@ func TestOAuth2CodeFlow(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + logger := &logrus.Logger{ + Out: os.Stderr, + Formatter: &logrus.TextFormatter{DisableColors: true}, + Level: logrus.DebugLevel, + } httpServer, s := newTestServer(ctx, t, func(c *Config) { c.Issuer = c.Issuer + "/non-root-path" c.Now = now c.IDTokensValidFor = idTokensValidFor // Create a new mock callback connector for each test case. - conn = mock.NewCallbackConnector().(*mock.Callback) + conn = mock.NewCallbackConnector(logger).(*mock.Callback) c.Connectors = []Connector{ { ID: "mock", @@ -743,7 +756,7 @@ func TestCrossClientScopes(t *testing.T) { } func TestPasswordDB(t *testing.T) { - s := memory.New() + s := memory.New(logger) conn := newPasswordDB(s) pw := "hi" @@ -840,7 +853,7 @@ func TestKeyCacher(t *testing.T) { tNow := time.Now() now := func() time.Time { return tNow } - s := memory.New() + s := memory.New(logger) tests := []struct { before func() diff --git a/storage/kubernetes/client.go b/storage/kubernetes/client.go index 55389f18..b21fb63d 100644 --- a/storage/kubernetes/client.go +++ b/storage/kubernetes/client.go @@ -21,6 +21,7 @@ import ( "strings" "time" + "github.com/Sirupsen/logrus" "github.com/ghodss/yaml" "github.com/gtank/cryptopasta" "golang.org/x/net/context" @@ -33,6 +34,7 @@ type client struct { client *http.Client baseURL string namespace string + logger logrus.FieldLogger // Hash function to map IDs (which could span a large range) to Kubernetes names. // While this is not currently upgradable, it could be in the future. @@ -230,7 +232,7 @@ func (c *client) put(resource, name string, v interface{}) error { return checkHTTPErr(resp, http.StatusOK) } -func newClient(cluster k8sapi.Cluster, user k8sapi.AuthInfo, namespace string) (*client, error) { +func newClient(cluster k8sapi.Cluster, user k8sapi.AuthInfo, namespace string, logger logrus.FieldLogger) (*client, error) { tlsConfig := cryptopasta.DefaultTLSConfig() data := func(b string, file string) ([]byte, error) { if b != "" { @@ -303,6 +305,7 @@ func newClient(cluster k8sapi.Cluster, user k8sapi.AuthInfo, namespace string) ( hash: func() hash.Hash { return fnv.New64() }, namespace: namespace, apiVersion: "oidc.coreos.com/v1", + logger: logger, }, nil } diff --git a/storage/kubernetes/storage.go b/storage/kubernetes/storage.go index 54712652..f3821ee1 100644 --- a/storage/kubernetes/storage.go +++ b/storage/kubernetes/storage.go @@ -10,6 +10,7 @@ import ( "golang.org/x/net/context" + "github.com/Sirupsen/logrus" "github.com/coreos/dex/storage" "github.com/coreos/dex/storage/kubernetes/k8sapi" ) @@ -39,8 +40,8 @@ type Config struct { } // Open returns a storage using Kubernetes third party resource. -func (c *Config) Open() (storage.Storage, error) { - cli, err := c.open() +func (c *Config) Open(logger logrus.FieldLogger) (storage.Storage, error) { + cli, err := c.open(logger) if err != nil { return nil, err } @@ -48,7 +49,7 @@ func (c *Config) Open() (storage.Storage, error) { } // open returns a client with no garbage collection. -func (c *Config) open() (*client, error) { +func (c *Config) open(logger logrus.FieldLogger) (*client, error) { if c.InCluster && (c.KubeConfigFile != "") { return nil, errors.New("cannot specify both 'inCluster' and 'kubeConfigFile'") } @@ -71,7 +72,7 @@ func (c *Config) open() (*client, error) { return nil, err } - cli, err := newClient(cluster, user, namespace) + cli, err := newClient(cluster, user, namespace, logger) if err != nil { return nil, fmt.Errorf("create client: %v", err) } diff --git a/storage/kubernetes/storage_test.go b/storage/kubernetes/storage_test.go index 769bba65..dae641e8 100644 --- a/storage/kubernetes/storage_test.go +++ b/storage/kubernetes/storage_test.go @@ -5,6 +5,7 @@ import ( "os" "testing" + "github.com/Sirupsen/logrus" "github.com/coreos/dex/storage" "github.com/coreos/dex/storage/conformance" ) @@ -22,7 +23,12 @@ func loadClient(t *testing.T) *client { if config.KubeConfigFile == "" { t.Skipf("test environment variable %q not set, skipping", testKubeConfigEnv) } - s, err := config.open() + logger := &logrus.Logger{ + Out: os.Stderr, + Formatter: &logrus.TextFormatter{DisableColors: true}, + Level: logrus.DebugLevel, + } + s, err := config.open(logger) if err != nil { t.Fatal(err) } diff --git a/storage/memory/memory.go b/storage/memory/memory.go index e8f2ce9a..6d609717 100644 --- a/storage/memory/memory.go +++ b/storage/memory/memory.go @@ -6,17 +6,19 @@ import ( "sync" "time" + "github.com/Sirupsen/logrus" "github.com/coreos/dex/storage" ) // New returns an in memory storage. -func New() storage.Storage { +func New(logger logrus.FieldLogger) storage.Storage { return &memStorage{ clients: make(map[string]storage.Client), authCodes: make(map[string]storage.AuthCode), refreshTokens: make(map[string]storage.RefreshToken), authReqs: make(map[string]storage.AuthRequest), passwords: make(map[string]storage.Password), + logger: logger, } } @@ -28,8 +30,8 @@ type Config struct { } // Open always returns a new in memory storage. -func (c *Config) Open() (storage.Storage, error) { - return New(), nil +func (c *Config) Open(logger logrus.FieldLogger) (storage.Storage, error) { + return New(logger), nil } type memStorage struct { @@ -42,6 +44,8 @@ type memStorage struct { passwords map[string]storage.Password keys storage.Keys + + logger logrus.FieldLogger } func (s *memStorage) tx(f func()) { diff --git a/storage/memory/memory_test.go b/storage/memory/memory_test.go index faa76283..aab63ffc 100644 --- a/storage/memory/memory_test.go +++ b/storage/memory/memory_test.go @@ -1,11 +1,23 @@ package memory import ( + "os" "testing" + "github.com/Sirupsen/logrus" + "github.com/coreos/dex/storage" "github.com/coreos/dex/storage/conformance" ) func TestStorage(t *testing.T) { - conformance.RunTests(t, New) + logger := &logrus.Logger{ + Out: os.Stderr, + Formatter: &logrus.TextFormatter{DisableColors: true}, + Level: logrus.DebugLevel, + } + + newStorage := func() storage.Storage { + return New(logger) + } + conformance.RunTests(t, newStorage) } diff --git a/storage/memory/static_clients_test.go b/storage/memory/static_clients_test.go index f85cad16..aab8597e 100644 --- a/storage/memory/static_clients_test.go +++ b/storage/memory/static_clients_test.go @@ -1,14 +1,21 @@ package memory import ( + "os" "reflect" "testing" + "github.com/Sirupsen/logrus" "github.com/coreos/dex/storage" ) func TestStaticClients(t *testing.T) { - s := New() + logger := &logrus.Logger{ + Out: os.Stderr, + Formatter: &logrus.TextFormatter{DisableColors: true}, + Level: logrus.DebugLevel, + } + s := New(logger) c1 := storage.Client{ID: "foo", Secret: "foo_secret"} c2 := storage.Client{ID: "bar", Secret: "bar_secret"} diff --git a/storage/sql/config.go b/storage/sql/config.go index 071f0b03..d77e5481 100644 --- a/storage/sql/config.go +++ b/storage/sql/config.go @@ -6,6 +6,7 @@ import ( "net/url" "strconv" + "github.com/Sirupsen/logrus" "github.com/coreos/dex/storage" ) @@ -16,15 +17,15 @@ type SQLite3 struct { } // Open creates a new storage implementation backed by SQLite3 -func (s *SQLite3) Open() (storage.Storage, error) { - conn, err := s.open() +func (s *SQLite3) Open(logger logrus.FieldLogger) (storage.Storage, error) { + conn, err := s.open(logger) if err != nil { return nil, err } return conn, nil } -func (s *SQLite3) open() (*conn, error) { +func (s *SQLite3) open(logger logrus.FieldLogger) (*conn, error) { db, err := sql.Open("sqlite3", s.File) if err != nil { return nil, err @@ -34,7 +35,7 @@ func (s *SQLite3) open() (*conn, error) { // doesn't support this, so limit the number of connections to 1. db.SetMaxOpenConns(1) } - c := &conn{db, flavorSQLite3} + c := &conn{db, flavorSQLite3, logger} if _, err := c.migrate(); err != nil { return nil, fmt.Errorf("failed to perform migrations: %v", err) } @@ -70,15 +71,15 @@ type Postgres struct { } // Open creates a new storage implementation backed by Postgres. -func (p *Postgres) Open() (storage.Storage, error) { - conn, err := p.open() +func (p *Postgres) Open(logger logrus.FieldLogger) (storage.Storage, error) { + conn, err := p.open(logger) if err != nil { return nil, err } return conn, nil } -func (p *Postgres) open() (*conn, error) { +func (p *Postgres) open(logger logrus.FieldLogger) (*conn, error) { v := url.Values{} set := func(key, val string) { if val != "" { @@ -113,7 +114,7 @@ func (p *Postgres) open() (*conn, error) { if err != nil { return nil, err } - c := &conn{db, flavorPostgres} + c := &conn{db, flavorPostgres, logger} if _, err := c.migrate(); err != nil { return nil, fmt.Errorf("failed to perform migrations: %v", err) } diff --git a/storage/sql/config_test.go b/storage/sql/config_test.go index 1afcf520..a91195cc 100644 --- a/storage/sql/config_test.go +++ b/storage/sql/config_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/Sirupsen/logrus" "github.com/coreos/dex/storage" "github.com/coreos/dex/storage/conformance" ) @@ -41,13 +42,19 @@ func cleanDB(c *conn) error { return err } +var logger = &logrus.Logger{ + Out: os.Stderr, + Formatter: &logrus.TextFormatter{DisableColors: true}, + Level: logrus.DebugLevel, +} + func TestSQLite3(t *testing.T) { newStorage := func() storage.Storage { // NOTE(ericchiang): In memory means we only get one connection at a time. If we // ever write tests that require using multiple connections, for instance to test // transactions, we need to move to a file based system. s := &SQLite3{":memory:"} - conn, err := s.open() + conn, err := s.open(logger) if err != nil { fmt.Fprintln(os.Stdout, err) t.Fatal(err) @@ -92,7 +99,7 @@ func TestPostgres(t *testing.T) { } newStorage := func() storage.Storage { - conn, err := p.open() + conn, err := p.open(logger) if err != nil { fatal(err) } diff --git a/storage/sql/migrate_test.go b/storage/sql/migrate_test.go index 6c0765a8..d46839f1 100644 --- a/storage/sql/migrate_test.go +++ b/storage/sql/migrate_test.go @@ -2,7 +2,10 @@ package sql import ( "database/sql" + "os" "testing" + + "github.com/Sirupsen/logrus" ) func TestMigrate(t *testing.T) { @@ -12,7 +15,13 @@ func TestMigrate(t *testing.T) { } defer db.Close() - c := &conn{db, flavorSQLite3} + logger := &logrus.Logger{ + Out: os.Stderr, + Formatter: &logrus.TextFormatter{DisableColors: true}, + Level: logrus.DebugLevel, + } + + c := &conn{db, flavorSQLite3, logger} for _, want := range []int{len(migrations), 0} { got, err := c.migrate() if err != nil { diff --git a/storage/sql/sql.go b/storage/sql/sql.go index 02cc4f4a..c1f57b0e 100644 --- a/storage/sql/sql.go +++ b/storage/sql/sql.go @@ -5,6 +5,7 @@ import ( "database/sql" "regexp" + "github.com/Sirupsen/logrus" "github.com/cockroachdb/cockroach-go/crdb" // import third party drivers @@ -110,6 +111,7 @@ func (f flavor) translate(query string) string { type conn struct { db *sql.DB flavor flavor + logger logrus.FieldLogger } func (c *conn) Close() error {