diff --git a/cmd/dex/config.go b/cmd/dex/config.go
index 0071b4fdd27edffaee30194e4e9c8ce3975d2157..ed1cc9f26fec93d2683978ede83168c8c9174ae4 100644
--- a/cmd/dex/config.go
+++ b/cmd/dex/config.go
@@ -6,9 +6,9 @@ import (
 	"fmt"
 	"os"
 
-	"github.com/sirupsen/logrus"
 	"golang.org/x/crypto/bcrypt"
 
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/server"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/etcd"
@@ -127,7 +127,7 @@ type Storage struct {
 
 // StorageConfig is a configuration that can create a storage.
 type StorageConfig interface {
-	Open(logrus.FieldLogger) (storage.Storage, error)
+	Open(logger log.Logger) (storage.Storage, error)
 }
 
 var storages = map[string]func() StorageConfig{
diff --git a/cmd/dex/serve.go b/cmd/dex/serve.go
index b9f940cc1581befc893d5c03d116dea153ae5a6d..0933eb4fa945cbcd3f3d948b8224d054903aaa0e 100644
--- a/cmd/dex/serve.go
+++ b/cmd/dex/serve.go
@@ -23,6 +23,7 @@ import (
 	"google.golang.org/grpc/credentials"
 
 	"github.com/dexidp/dex/api"
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/server"
 	"github.com/dexidp/dex/storage"
 )
@@ -324,7 +325,7 @@ func (f *utcFormatter) Format(e *logrus.Entry) ([]byte, error) {
 	return f.f.Format(e)
 }
 
-func newLogger(level string, format string) (logrus.FieldLogger, error) {
+func newLogger(level string, format string) (log.Logger, error) {
 	var logLevel logrus.Level
 	switch strings.ToLower(level) {
 	case "debug":
@@ -347,9 +348,9 @@ func newLogger(level string, format string) (logrus.FieldLogger, error) {
 		return nil, fmt.Errorf("log format is not one of the supported values (%s): %s", strings.Join(logFormats, ", "), format)
 	}
 
-	return &logrus.Logger{
+	return log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &formatter,
 		Level:     logLevel,
-	}, nil
+	}), nil
 }
diff --git a/connector/authproxy/authproxy.go b/connector/authproxy/authproxy.go
index b4f3958d7ba60e8ecd4e07aee4758292bddcf253..f58c4b685ec863461094270850d695a7c368d7cf 100644
--- a/connector/authproxy/authproxy.go
+++ b/connector/authproxy/authproxy.go
@@ -8,9 +8,8 @@ import (
 	"net/http"
 	"net/url"
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/dexidp/dex/connector"
+	"github.com/dexidp/dex/pkg/log"
 )
 
 // Config holds the configuration parameters for a connector which returns an
@@ -18,14 +17,14 @@ import (
 type Config struct{}
 
 // Open returns an authentication strategy which requires no user interaction.
-func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) {
+func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
 	return &callback{logger: logger, pathSuffix: "/" + id}, nil
 }
 
 // Callback is a connector which returns an identity with the HTTP header
 // X-Remote-User as verified email.
 type callback struct {
-	logger     logrus.FieldLogger
+	logger     log.Logger
 	pathSuffix string
 }
 
diff --git a/connector/bitbucketcloud/bitbucketcloud.go b/connector/bitbucketcloud/bitbucketcloud.go
index 27a63c4684169d54550f55168fac040f589b5b1e..6c391be76f5769924006eda29d4b588d7bca2ee8 100644
--- a/connector/bitbucketcloud/bitbucketcloud.go
+++ b/connector/bitbucketcloud/bitbucketcloud.go
@@ -6,6 +6,7 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"github.com/dexidp/dex/pkg/log"
 	"io/ioutil"
 	"net/http"
 	"sync"
@@ -14,8 +15,6 @@ import (
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2/bitbucket"
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/dexidp/dex/connector"
 )
 
@@ -40,7 +39,7 @@ type Config struct {
 }
 
 // Open returns a strategy for logging in through Bitbucket.
-func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) {
+func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
 
 	b := bitbucketConnector{
 		redirectURI:  c.RedirectURI,
@@ -70,7 +69,7 @@ type bitbucketConnector struct {
 	teams        []string
 	clientID     string
 	clientSecret string
-	logger       logrus.FieldLogger
+	logger       log.Logger
 	apiURL       string
 
 	// the following are used only for tests
diff --git a/connector/github/github.go b/connector/github/github.go
index 9f7c2782a9926f2535b6b790ab657180aed3ddc9..8658f8cdee1959175b6d6ba1eea05ff2332e7b51 100644
--- a/connector/github/github.go
+++ b/connector/github/github.go
@@ -16,11 +16,11 @@ import (
 	"strings"
 	"time"
 
-	"github.com/sirupsen/logrus"
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2/github"
 
 	"github.com/dexidp/dex/connector"
+	"github.com/dexidp/dex/pkg/log"
 )
 
 const (
@@ -53,7 +53,6 @@ type Config struct {
 
 // Org holds org-team filters, in which teams are optional.
 type Org struct {
-
 	// Organization name in github (not slug, full name). Only users in this github
 	// organization can authenticate.
 	Name string `json:"name"`
@@ -66,14 +65,14 @@ type Org struct {
 }
 
 // Open returns a strategy for logging in through GitHub.
-func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) {
+func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
 
 	if c.Org != "" {
 		// Return error if both 'org' and 'orgs' fields are used.
 		if len(c.Orgs) > 0 {
 			return nil, errors.New("github: cannot use both 'org' and 'orgs' fields simultaneously")
 		}
-		logger.Warnln("github: legacy field 'org' being used. Switch to the newer 'orgs' field structure")
+		logger.Warn("github: legacy field 'org' being used. Switch to the newer 'orgs' field structure")
 	}
 
 	g := githubConnector{
@@ -137,7 +136,7 @@ type githubConnector struct {
 	orgs         []Org
 	clientID     string
 	clientSecret string
-	logger       logrus.FieldLogger
+	logger       log.Logger
 	// apiURL defaults to "https://api.github.com"
 	apiURL string
 	// hostName of the GitHub enterprise account.
diff --git a/connector/gitlab/gitlab.go b/connector/gitlab/gitlab.go
index 41b0beb26154da99623c563a325d9a52801b3fcb..58ecba17f54a7932f9773134f5243c3a884c17b9 100644
--- a/connector/gitlab/gitlab.go
+++ b/connector/gitlab/gitlab.go
@@ -10,10 +10,10 @@ import (
 	"net/http"
 	"strconv"
 
-	"github.com/sirupsen/logrus"
 	"golang.org/x/oauth2"
 
 	"github.com/dexidp/dex/connector"
+	"github.com/dexidp/dex/pkg/log"
 )
 
 const (
@@ -42,7 +42,7 @@ type gitlabUser struct {
 }
 
 // Open returns a strategy for logging in through GitLab.
-func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) {
+func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
 	if c.BaseURL == "" {
 		c.BaseURL = "https://gitlab.com"
 	}
@@ -71,7 +71,7 @@ type gitlabConnector struct {
 	org          string
 	clientID     string
 	clientSecret string
-	logger       logrus.FieldLogger
+	logger       log.Logger
 }
 
 func (c *gitlabConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
diff --git a/connector/keystone/keystone.go b/connector/keystone/keystone.go
index a86e957d577fc35872dc8e44419fe52d7dde3c2b..0a2440db1d28b2fc24c7680f1c14df96ee8b8260 100644
--- a/connector/keystone/keystone.go
+++ b/connector/keystone/keystone.go
@@ -9,9 +9,8 @@ import (
 	"io/ioutil"
 	"net/http"
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/dexidp/dex/connector"
+	"github.com/dexidp/dex/pkg/log"
 )
 
 type conn struct {
@@ -19,7 +18,7 @@ type conn struct {
 	Host          string
 	AdminUsername string
 	AdminPassword string
-	Logger        logrus.FieldLogger
+	Logger        log.Logger
 }
 
 type userKeystone struct {
@@ -102,7 +101,7 @@ var (
 )
 
 // Open returns an authentication strategy using Keystone.
-func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) {
+func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
 	return &conn{
 		c.Domain,
 		c.Host,
diff --git a/connector/ldap/ldap.go b/connector/ldap/ldap.go
index a7aa6c4fa8e6df0cd9624adfbbbf9aa1aabd776a..cf8e5006ff28a11bafc58eec0b7ab8e08dbd714d 100644
--- a/connector/ldap/ldap.go
+++ b/connector/ldap/ldap.go
@@ -12,9 +12,8 @@ import (
 
 	"gopkg.in/ldap.v2"
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/dexidp/dex/connector"
+	"github.com/dexidp/dex/pkg/log"
 )
 
 // Config holds the configuration parameters for the LDAP connector. The LDAP
@@ -165,7 +164,7 @@ func parseScope(s string) (int, bool) {
 }
 
 // Open returns an authentication strategy using LDAP.
-func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) {
+func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
 	conn, err := c.OpenConnector(logger)
 	if err != nil {
 		return nil, err
@@ -179,7 +178,7 @@ type refreshData struct {
 }
 
 // OpenConnector is the same as Open but returns a type with all implemented connector interfaces.
-func (c *Config) OpenConnector(logger logrus.FieldLogger) (interface {
+func (c *Config) OpenConnector(logger log.Logger) (interface {
 	connector.Connector
 	connector.PasswordConnector
 	connector.RefreshConnector
@@ -187,7 +186,7 @@ func (c *Config) OpenConnector(logger logrus.FieldLogger) (interface {
 	return c.openConnector(logger)
 }
 
-func (c *Config) openConnector(logger logrus.FieldLogger) (*ldapConnector, error) {
+func (c *Config) openConnector(logger log.Logger) (*ldapConnector, error) {
 
 	requiredFields := []struct {
 		name string
@@ -259,7 +258,7 @@ type ldapConnector struct {
 
 	tlsConfig *tls.Config
 
-	logger logrus.FieldLogger
+	logger log.Logger
 }
 
 var (
diff --git a/connector/ldap/ldap_test.go b/connector/ldap/ldap_test.go
index fa6b706246189c5decfe7c7812aae5051759d95b..c6f308077545c741fc3707b5e60887440a3590b5 100644
--- a/connector/ldap/ldap_test.go
+++ b/connector/ldap/ldap_test.go
@@ -17,6 +17,7 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/dexidp/dex/connector"
+	"github.com/dexidp/dex/pkg/log"
 )
 
 const envVar = "DEX_LDAP_TESTS"
@@ -875,7 +876,7 @@ func runTests(t *testing.T, schema string, connMethod connectionMethod, config *
 	c.BindDN = "cn=admin,dc=example,dc=org"
 	c.BindPW = "admin"
 
-	l := &logrus.Logger{Out: ioutil.Discard, Formatter: &logrus.TextFormatter{}}
+	l := log.NewLogrusLogger(&logrus.Logger{Out: ioutil.Discard, Formatter: &logrus.TextFormatter{}})
 
 	conn, err := c.openConnector(l)
 	if err != nil {
diff --git a/connector/linkedin/linkedin.go b/connector/linkedin/linkedin.go
index 9ab67e57c849efdeec981509ffd297e9f61a4b60..df5725b3e1b6642a4faaf82fe2fb9716f3aacffc 100644
--- a/connector/linkedin/linkedin.go
+++ b/connector/linkedin/linkedin.go
@@ -11,9 +11,8 @@ import (
 
 	"golang.org/x/oauth2"
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/dexidp/dex/connector"
+	"github.com/dexidp/dex/pkg/log"
 )
 
 const (
@@ -30,7 +29,7 @@ type Config struct {
 }
 
 // Open returns a strategy for logging in through LinkedIn
-func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) {
+func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
 	return &linkedInConnector{
 		oauth2Config: &oauth2.Config{
 			ClientID:     c.ClientID,
@@ -52,7 +51,7 @@ type connectorData struct {
 
 type linkedInConnector struct {
 	oauth2Config *oauth2.Config
-	logger       logrus.FieldLogger
+	logger       log.Logger
 }
 
 // LinkedIn doesn't provide refresh tokens, so refresh tokens issued by Dex
diff --git a/connector/microsoft/microsoft.go b/connector/microsoft/microsoft.go
index ad6b3e73047a77fb41b806d0658ab3bd88a9058b..730c77e36748ffa9af11d352b87e7621c5bef283 100644
--- a/connector/microsoft/microsoft.go
+++ b/connector/microsoft/microsoft.go
@@ -14,9 +14,8 @@ import (
 
 	"golang.org/x/oauth2"
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/dexidp/dex/connector"
+	"github.com/dexidp/dex/pkg/log"
 )
 
 const (
@@ -39,7 +38,7 @@ type Config struct {
 }
 
 // Open returns a strategy for logging in through Microsoft.
-func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) {
+func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
 	m := microsoftConnector{
 		redirectURI:        c.RedirectURI,
 		clientID:           c.ClientID,
@@ -76,7 +75,7 @@ type microsoftConnector struct {
 	tenant             string
 	onlySecurityGroups bool
 	groups             []string
-	logger             logrus.FieldLogger
+	logger             log.Logger
 }
 
 func (c *microsoftConnector) isOrgTenant() bool {
diff --git a/connector/mock/connectortest.go b/connector/mock/connectortest.go
index ef8afd460826a862fed964b30258de3707761f4f..5089914ca19aa3eb196f43e5ae6488bbbc005c5e 100644
--- a/connector/mock/connectortest.go
+++ b/connector/mock/connectortest.go
@@ -8,14 +8,13 @@ import (
 	"net/http"
 	"net/url"
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/dexidp/dex/connector"
+	"github.com/dexidp/dex/pkg/log"
 )
 
 // NewCallbackConnector returns a mock connector which requires no user interaction. It always returns
 // the same (fake) identity.
-func NewCallbackConnector(logger logrus.FieldLogger) connector.Connector {
+func NewCallbackConnector(logger log.Logger) connector.Connector {
 	return &Callback{
 		Identity: connector.Identity{
 			UserID:        "0-385-28089-0",
@@ -40,7 +39,7 @@ var (
 type Callback struct {
 	// The returned identity.
 	Identity connector.Identity
-	Logger   logrus.FieldLogger
+	Logger   log.Logger
 }
 
 // LoginURL returns the URL to redirect the user to login with.
@@ -71,7 +70,7 @@ 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(id string, logger logrus.FieldLogger) (connector.Connector, error) {
+func (c *CallbackConfig) Open(id string, logger log.Logger) (connector.Connector, error) {
 	return NewCallbackConnector(logger), nil
 }
 
@@ -83,7 +82,7 @@ type PasswordConfig struct {
 }
 
 // Open returns an authentication strategy which prompts for a predefined username and password.
-func (c *PasswordConfig) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) {
+func (c *PasswordConfig) Open(id string, logger log.Logger) (connector.Connector, error) {
 	if c.Username == "" {
 		return nil, errors.New("no username supplied")
 	}
@@ -96,7 +95,7 @@ func (c *PasswordConfig) Open(id string, logger logrus.FieldLogger) (connector.C
 type passwordConnector struct {
 	username string
 	password string
-	logger   logrus.FieldLogger
+	logger   log.Logger
 }
 
 func (p passwordConnector) Close() error { return nil }
diff --git a/connector/oidc/oidc.go b/connector/oidc/oidc.go
index 4468edc4776a2341b6580aea86fe1bd711d4bc12..ac24acc9d452dd4d7cad44a4f80315fd7b6dad32 100644
--- a/connector/oidc/oidc.go
+++ b/connector/oidc/oidc.go
@@ -11,10 +11,10 @@ import (
 	"sync"
 
 	"github.com/coreos/go-oidc"
-	"github.com/sirupsen/logrus"
 	"golang.org/x/oauth2"
 
 	"github.com/dexidp/dex/connector"
+	"github.com/dexidp/dex/pkg/log"
 )
 
 // Config holds configuration options for OpenID Connect logins.
@@ -75,7 +75,7 @@ func registerBrokenAuthHeaderProvider(url string) {
 
 // Open returns a connector which can be used to login users through an upstream
 // OpenID Connect provider.
-func (c *Config) Open(id string, logger logrus.FieldLogger) (conn connector.Connector, err error) {
+func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, err error) {
 	ctx, cancel := context.WithCancel(context.Background())
 
 	provider, err := oidc.NewProvider(ctx, c.Issuer)
@@ -130,7 +130,7 @@ type oidcConnector struct {
 	verifier      *oidc.IDTokenVerifier
 	ctx           context.Context
 	cancel        context.CancelFunc
-	logger        logrus.FieldLogger
+	logger        log.Logger
 	hostedDomains []string
 }
 
diff --git a/connector/saml/saml.go b/connector/saml/saml.go
index 2b092b3f80198cb019e8fc0fb137e74304368771..3358583db1b01d29c8b0ca6908138f8902fda287 100644
--- a/connector/saml/saml.go
+++ b/connector/saml/saml.go
@@ -14,11 +14,10 @@ import (
 	"time"
 
 	"github.com/beevik/etree"
+	"github.com/dexidp/dex/connector"
+	"github.com/dexidp/dex/pkg/log"
 	dsig "github.com/russellhaering/goxmldsig"
 	"github.com/russellhaering/goxmldsig/etreeutils"
-	"github.com/sirupsen/logrus"
-
-	"github.com/dexidp/dex/connector"
 )
 
 const (
@@ -126,11 +125,11 @@ func (c certStore) Certificates() (roots []*x509.Certificate, err error) {
 
 // Open validates the config and returns a connector. It does not actually
 // validate connectivity with the provider.
-func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) {
+func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
 	return c.openConnector(logger)
 }
 
-func (c *Config) openConnector(logger logrus.FieldLogger) (*provider, error) {
+func (c *Config) openConnector(logger log.Logger) (*provider, error) {
 	requiredFields := []struct {
 		name, val string
 	}{
@@ -241,7 +240,7 @@ type provider struct {
 
 	nameIDPolicyFormat string
 
-	logger logrus.FieldLogger
+	logger log.Logger
 }
 
 func (p *provider) POSTData(s connector.Scopes, id string) (action, value string, err error) {
diff --git a/connector/saml/saml_test.go b/connector/saml/saml_test.go
index 4497d059c3e577577d398d8debb0d011f05b2e71..e7ccbbb83993255f09960ade495a5ee02863881f 100644
--- a/connector/saml/saml_test.go
+++ b/connector/saml/saml_test.go
@@ -5,6 +5,7 @@ import (
 	"encoding/base64"
 	"encoding/pem"
 	"errors"
+	"github.com/dexidp/dex/pkg/log"
 	"io/ioutil"
 	"sort"
 	"testing"
@@ -304,7 +305,7 @@ func (r responseTest) run(t *testing.T) {
 		t.Fatalf("parse test time: %v", err)
 	}
 
-	conn, err := c.openConnector(logrus.New())
+	conn, err := c.openConnector(log.NewLogrusLogger(logrus.New()))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -338,7 +339,7 @@ func (r responseTest) run(t *testing.T) {
 }
 
 func TestConfigCAData(t *testing.T) {
-	logger := logrus.New()
+	logger := log.NewLogrusLogger(logrus.New())
 	validPEM, err := ioutil.ReadFile("testdata/ca.crt")
 	if err != nil {
 		t.Fatal(err)
@@ -475,7 +476,7 @@ func newProvider(ssoIssuer string, redirectURI string) *provider {
 		usernameAttr: "user",
 		emailAttr:    "email",
 		redirectURI:  redirectURI,
-		logger:       logrus.New(),
+		logger:       log.NewLogrusLogger(logrus.New()),
 	}
 }
 
diff --git a/pkg/log/logger.go b/pkg/log/logger.go
new file mode 100644
index 0000000000000000000000000000000000000000..60a651b478b410553d17f1bc50dbe4e38542f785
--- /dev/null
+++ b/pkg/log/logger.go
@@ -0,0 +1,17 @@
+// Package log provides a logger interface for logger libraries
+// so that dex does not depend on any of them directly.
+// It also includes a default implementation using Logrus (used by dex previously).
+package log
+
+// Logger serves as an adapter interface for logger libraries
+// so that dex does not depend on any of them directly.
+type Logger interface {
+	WithField(key string, value interface{}) Logger
+
+	Info(msg string)
+	Warn(msg string)
+
+	Debugf(format string, args ...interface{})
+	Infof(format string, args ...interface{})
+	Errorf(format string, args ...interface{})
+}
diff --git a/pkg/log/logrus.go b/pkg/log/logrus.go
new file mode 100644
index 0000000000000000000000000000000000000000..4efd6482fac0f568c05f467dcdbe33ab0caa1ca9
--- /dev/null
+++ b/pkg/log/logrus.go
@@ -0,0 +1,45 @@
+package log
+
+import "github.com/sirupsen/logrus"
+
+// LogrusLogger is an adapter for Logrus implementing the Logger interface.
+type LogrusLogger struct {
+	logger logrus.FieldLogger
+}
+
+// NewLogrusLogger returns a new Logger wrapping Logrus.
+func NewLogrusLogger(logger logrus.FieldLogger) *LogrusLogger {
+	return &LogrusLogger{
+		logger: logger,
+	}
+}
+
+// WithField adds a field to the log entry.
+func (l *LogrusLogger) WithField(key string, value interface{}) Logger {
+	return NewLogrusLogger(l.logger.WithField(key, value))
+}
+
+// Info logs an Info level event.
+func (l *LogrusLogger) Info(msg string) {
+	l.logger.Info(msg)
+}
+
+// Warn logs a Warn level event.
+func (l *LogrusLogger) Warn(msg string) {
+	l.logger.Warn(msg)
+}
+
+// Debugf formats and logs a Debug level event.
+func (l *LogrusLogger) Debugf(format string, args ...interface{}) {
+	l.logger.Debugf(format, args...)
+}
+
+// Infof formats and logs an Info level event.
+func (l *LogrusLogger) Infof(format string, args ...interface{}) {
+	l.logger.Infof(format, args...)
+}
+
+// Errorf formats and logs n Error level event.
+func (l *LogrusLogger) Errorf(format string, args ...interface{}) {
+	l.logger.Errorf(format, args...)
+}
diff --git a/pkg/log/logrus_test.go b/pkg/log/logrus_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..cb60c6b9764748498e42bd2c6c18f6fbf233eeb5
--- /dev/null
+++ b/pkg/log/logrus_test.go
@@ -0,0 +1,10 @@
+package log
+
+import "testing"
+
+func TestLogrusLoggerImplementsLoggerInterface(t *testing.T) {
+	var i interface{} = new(LogrusLogger)
+	if _, ok := i.(Logger); !ok {
+		t.Errorf("expected %T to implement Logger interface", i)
+	}
+}
diff --git a/server/api.go b/server/api.go
index c1107e4c9a37d4a2220d02eba2edfd5b74770d7b..f900cd1c96800a6fcb3b78b2e9f17d1073fd08c4 100644
--- a/server/api.go
+++ b/server/api.go
@@ -10,9 +10,8 @@ import (
 	// https://github.com/grpc/grpc-go/issues/711
 	"golang.org/x/net/context"
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/dexidp/dex/api"
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/server/internal"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/version"
@@ -34,7 +33,7 @@ const (
 )
 
 // NewAPI returns a server which implements the gRPC API interface.
-func NewAPI(s storage.Storage, logger logrus.FieldLogger) api.DexServer {
+func NewAPI(s storage.Storage, logger log.Logger) api.DexServer {
 	return dexAPI{
 		s:      s,
 		logger: logger,
@@ -43,7 +42,7 @@ func NewAPI(s storage.Storage, logger logrus.FieldLogger) api.DexServer {
 
 type dexAPI struct {
 	s      storage.Storage
-	logger logrus.FieldLogger
+	logger log.Logger
 }
 
 func (d dexAPI) CreateClient(ctx context.Context, req *api.CreateClientReq) (*api.CreateClientResp, error) {
diff --git a/server/api_test.go b/server/api_test.go
index 14759e63d303f08882d931b4746871347eca031b..dbd67b0a1230ac5cff4b9e2c8573bcc354a9b50f 100644
--- a/server/api_test.go
+++ b/server/api_test.go
@@ -11,6 +11,7 @@ import (
 	"google.golang.org/grpc"
 
 	"github.com/dexidp/dex/api"
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/server/internal"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/memory"
@@ -28,7 +29,7 @@ type apiClient struct {
 }
 
 // newAPI constructs a gRCP client connected to a backing server.
-func newAPI(s storage.Storage, logger logrus.FieldLogger, t *testing.T) *apiClient {
+func newAPI(s storage.Storage, logger log.Logger, t *testing.T) *apiClient {
 	l, err := net.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
 		t.Fatal(err)
@@ -57,11 +58,11 @@ func newAPI(s storage.Storage, logger logrus.FieldLogger, t *testing.T) *apiClie
 
 // Attempts to create, update and delete a test Password
 func TestPassword(t *testing.T) {
-	logger := &logrus.Logger{
+	logger := log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &logrus.TextFormatter{DisableColors: true},
 		Level:     logrus.DebugLevel,
-	}
+	})
 
 	s := memory.New(logger)
 	client := newAPI(s, logger, t)
@@ -122,11 +123,11 @@ func TestPassword(t *testing.T) {
 
 // Ensures checkCost returns expected values
 func TestCheckCost(t *testing.T) {
-	logger := &logrus.Logger{
+	logger := log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &logrus.TextFormatter{DisableColors: true},
 		Level:     logrus.DebugLevel,
-	}
+	})
 
 	s := memory.New(logger)
 	client := newAPI(s, logger, t)
@@ -179,11 +180,11 @@ func TestCheckCost(t *testing.T) {
 
 // Attempts to list and revoke an exisiting refresh token.
 func TestRefreshToken(t *testing.T) {
-	logger := &logrus.Logger{
+	logger := log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &logrus.TextFormatter{DisableColors: true},
 		Level:     logrus.DebugLevel,
-	}
+	})
 
 	s := memory.New(logger)
 	client := newAPI(s, logger, t)
@@ -292,11 +293,11 @@ func TestRefreshToken(t *testing.T) {
 }
 
 func TestUpdateClient(t *testing.T) {
-	logger := &logrus.Logger{
+	logger := log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &logrus.TextFormatter{DisableColors: true},
 		Level:     logrus.DebugLevel,
-	}
+	})
 
 	s := memory.New(logger)
 	client := newAPI(s, logger, t)
diff --git a/server/rotation.go b/server/rotation.go
index bb857450d663dda5466b72c3625941dbed3d1e7d..579fe3d17f3d977c3b93cf3a70d01486ad09d4a8 100644
--- a/server/rotation.go
+++ b/server/rotation.go
@@ -12,8 +12,7 @@ import (
 
 	"gopkg.in/square/go-jose.v2"
 
-	"github.com/sirupsen/logrus"
-
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 )
 
@@ -62,7 +61,7 @@ type keyRotater struct {
 	strategy rotationStrategy
 	now      func() time.Time
 
-	logger logrus.FieldLogger
+	logger log.Logger
 }
 
 // startKeyRotation begins key rotation in a new goroutine, closing once the context is canceled.
diff --git a/server/rotation_test.go b/server/rotation_test.go
index 66c269cefef1fc920a183c7027c6b3cd3401960c..f77ec783252b9ffa88bd2910c3dbcdde0f77db84 100644
--- a/server/rotation_test.go
+++ b/server/rotation_test.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/sirupsen/logrus"
 
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/memory"
 )
@@ -67,11 +68,11 @@ func TestKeyRotater(t *testing.T) {
 	// Only the last 5 verification keys are expected to be kept around.
 	maxVerificationKeys := 5
 
-	l := &logrus.Logger{
+	l := log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &logrus.TextFormatter{DisableColors: true},
 		Level:     logrus.DebugLevel,
-	}
+	})
 
 	r := &keyRotater{
 		Storage:  memory.New(l),
diff --git a/server/server.go b/server/server.go
index 58968a1b66e5c3cc24cfd1171b877a530bd7e3ee..49d6fc2e06996524e31d2d1d7a92c521ef8c39e9 100644
--- a/server/server.go
+++ b/server/server.go
@@ -16,12 +16,6 @@ import (
 
 	"golang.org/x/crypto/bcrypt"
 
-	"github.com/felixge/httpsnoop"
-	"github.com/gorilla/handlers"
-	"github.com/gorilla/mux"
-	"github.com/prometheus/client_golang/prometheus"
-	"github.com/sirupsen/logrus"
-
 	"github.com/dexidp/dex/connector"
 	"github.com/dexidp/dex/connector/authproxy"
 	"github.com/dexidp/dex/connector/bitbucketcloud"
@@ -34,7 +28,12 @@ import (
 	"github.com/dexidp/dex/connector/mock"
 	"github.com/dexidp/dex/connector/oidc"
 	"github.com/dexidp/dex/connector/saml"
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
+	"github.com/felixge/httpsnoop"
+	"github.com/gorilla/handlers"
+	"github.com/gorilla/mux"
+	"github.com/prometheus/client_golang/prometheus"
 )
 
 // LocalConnector is the local passwordDB connector which is an internal
@@ -80,7 +79,7 @@ type Config struct {
 
 	Web WebConfig
 
-	Logger logrus.FieldLogger
+	Logger log.Logger
 
 	PrometheusRegistry *prometheus.Registry
 }
@@ -142,7 +141,7 @@ type Server struct {
 	idTokensValidFor     time.Duration
 	authRequestsValidFor time.Duration
 
-	logger logrus.FieldLogger
+	logger log.Logger
 }
 
 // NewServer constructs a server from the provided config.
@@ -431,7 +430,7 @@ func (s *Server) startGarbageCollection(ctx context.Context, frequency time.Dura
 
 // ConnectorConfig is a configuration that can open a connector.
 type ConnectorConfig interface {
-	Open(id string, logger logrus.FieldLogger) (connector.Connector, error)
+	Open(id string, logger log.Logger) (connector.Connector, error)
 }
 
 // ConnectorsConfig variable provides an easy way to return a config struct
@@ -454,7 +453,7 @@ var ConnectorsConfig = map[string]func() ConnectorConfig{
 }
 
 // openConnector will parse the connector config and open the connector.
-func openConnector(logger logrus.FieldLogger, conn storage.Connector) (connector.Connector, error) {
+func openConnector(logger log.Logger, conn storage.Connector) (connector.Connector, error) {
 	var c connector.Connector
 
 	f, ok := ConnectorsConfig[conn.Type]
diff --git a/server/server_test.go b/server/server_test.go
index 536387c40d41047f5f91ba80c2bcca49d527c934..1433162b09f8b8db472a381bd644b93befcb560f 100644
--- a/server/server_test.go
+++ b/server/server_test.go
@@ -30,6 +30,7 @@ import (
 
 	"github.com/dexidp/dex/connector"
 	"github.com/dexidp/dex/connector/mock"
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/memory"
 )
@@ -74,11 +75,11 @@ FDWV28nTP9sqbtsmU8Tem2jzMvZ7C/Q0AuDoKELFUpux8shm8wfIhyaPnXUGZoAZ
 Np4vUwMSYV5mopESLWOg3loBxKyLGFtgGKVCjGiQvy6zISQ4fQo=
 -----END RSA PRIVATE KEY-----`)
 
-var logger = &logrus.Logger{
+var logger = log.NewLogrusLogger(&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
diff --git a/storage/etcd/config.go b/storage/etcd/config.go
index 260ec257a7892c9376e9d9bbdf0b8ce50080686f..f36a11bb9d5d9d07a1ea74593c7b59eaee6910fc 100644
--- a/storage/etcd/config.go
+++ b/storage/etcd/config.go
@@ -6,8 +6,8 @@ import (
 	"github.com/coreos/etcd/clientv3"
 	"github.com/coreos/etcd/clientv3/namespace"
 	"github.com/coreos/etcd/pkg/transport"
-	"github.com/sirupsen/logrus"
 
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 )
 
@@ -36,11 +36,11 @@ type Etcd struct {
 }
 
 // Open creates a new storage implementation backed by Etcd
-func (p *Etcd) Open(logger logrus.FieldLogger) (storage.Storage, error) {
+func (p *Etcd) Open(logger log.Logger) (storage.Storage, error) {
 	return p.open(logger)
 }
 
-func (p *Etcd) open(logger logrus.FieldLogger) (*conn, error) {
+func (p *Etcd) open(logger log.Logger) (*conn, error) {
 	cfg := clientv3.Config{
 		Endpoints:   p.Endpoints,
 		DialTimeout: defaultDialTimeout,
diff --git a/storage/etcd/etcd.go b/storage/etcd/etcd.go
index e323f5ab9f97d138f2325f8957293cf4f4a664fd..d106f443d2120e772c1deeab1122037a7a04323f 100644
--- a/storage/etcd/etcd.go
+++ b/storage/etcd/etcd.go
@@ -8,8 +8,8 @@ import (
 	"time"
 
 	"github.com/coreos/etcd/clientv3"
-	"github.com/sirupsen/logrus"
 
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 )
 
@@ -29,7 +29,7 @@ const (
 
 type conn struct {
 	db     *clientv3.Client
-	logger logrus.FieldLogger
+	logger log.Logger
 }
 
 func (c *conn) Close() error {
diff --git a/storage/etcd/etcd_test.go b/storage/etcd/etcd_test.go
index bd41253649b7d83c9828b1f2531588974e5f081d..ac5ab175ee753a744c97f9fc909b6ff1afa08ea4 100644
--- a/storage/etcd/etcd_test.go
+++ b/storage/etcd/etcd_test.go
@@ -3,6 +3,7 @@ package etcd
 import (
 	"context"
 	"fmt"
+	"github.com/dexidp/dex/pkg/log"
 	"os"
 	"runtime"
 	"strings"
@@ -53,11 +54,11 @@ func cleanDB(c *conn) error {
 	return nil
 }
 
-var logger = &logrus.Logger{
+var logger = log.NewLogrusLogger(&logrus.Logger{
 	Out:       os.Stderr,
 	Formatter: &logrus.TextFormatter{DisableColors: true},
 	Level:     logrus.DebugLevel,
-}
+})
 
 func TestEtcd(t *testing.T) {
 	testEtcdEnv := "DEX_ETCD_ENDPOINTS"
diff --git a/storage/kubernetes/client.go b/storage/kubernetes/client.go
index cb7fd2802453853c4993495336243d1f43e97c77..d6d81f9865e8fff73b7e63929679572af6a45e44 100644
--- a/storage/kubernetes/client.go
+++ b/storage/kubernetes/client.go
@@ -24,9 +24,9 @@ import (
 
 	"github.com/ghodss/yaml"
 	"github.com/gtank/cryptopasta"
-	"github.com/sirupsen/logrus"
 	"golang.org/x/net/http2"
 
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/kubernetes/k8sapi"
 )
@@ -35,7 +35,7 @@ type client struct {
 	client    *http.Client
 	baseURL   string
 	namespace string
-	logger    logrus.FieldLogger
+	logger    log.Logger
 
 	// 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.
@@ -253,7 +253,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, logger logrus.FieldLogger, useTPR bool) (*client, error) {
+func newClient(cluster k8sapi.Cluster, user k8sapi.AuthInfo, namespace string, logger log.Logger, useTPR bool) (*client, error) {
 	tlsConfig := cryptopasta.DefaultTLSConfig()
 	data := func(b string, file string) ([]byte, error) {
 		if b != "" {
diff --git a/storage/kubernetes/storage.go b/storage/kubernetes/storage.go
index 86f3f209320292f797e9b95b8da7d026187ad6d9..193c050302db090f4a282bf7a46c71578bbd871b 100644
--- a/storage/kubernetes/storage.go
+++ b/storage/kubernetes/storage.go
@@ -7,8 +7,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/sirupsen/logrus"
-
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/kubernetes/k8sapi"
 )
@@ -43,7 +42,7 @@ type Config struct {
 }
 
 // Open returns a storage using Kubernetes third party resource.
-func (c *Config) Open(logger logrus.FieldLogger) (storage.Storage, error) {
+func (c *Config) Open(logger log.Logger) (storage.Storage, error) {
 	cli, err := c.open(logger, false)
 	if err != nil {
 		return nil, err
@@ -56,7 +55,7 @@ func (c *Config) Open(logger logrus.FieldLogger) (storage.Storage, error) {
 //
 // waitForResources controls if errors creating the resources cause this method to return
 // immediately (used during testing), or if the client will asynchronously retry.
-func (c *Config) open(logger logrus.FieldLogger, waitForResources bool) (*client, error) {
+func (c *Config) open(logger log.Logger, waitForResources bool) (*client, error) {
 	if c.InCluster && (c.KubeConfigFile != "") {
 		return nil, errors.New("cannot specify both 'inCluster' and 'kubeConfigFile'")
 	}
diff --git a/storage/kubernetes/storage_test.go b/storage/kubernetes/storage_test.go
index 27d65416f19aa88de9155464e943e064e92b2046..d6e4a1afa33c118c1ef1139ca028a06d0f4fcfee 100644
--- a/storage/kubernetes/storage_test.go
+++ b/storage/kubernetes/storage_test.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/sirupsen/logrus"
 
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/conformance"
 )
@@ -24,11 +25,11 @@ func loadClient(t *testing.T) *client {
 	if config.KubeConfigFile == "" {
 		t.Skipf("test environment variable %q not set, skipping", testKubeConfigEnv)
 	}
-	logger := &logrus.Logger{
+	logger := log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &logrus.TextFormatter{DisableColors: true},
 		Level:     logrus.DebugLevel,
-	}
+	})
 	s, err := config.open(logger, true)
 	if err != nil {
 		t.Fatal(err)
diff --git a/storage/memory/memory.go b/storage/memory/memory.go
index d8817fbda523a54510b135002015494998f5654e..681d204ea87791c20ea6488f3b5734d05abdc250 100644
--- a/storage/memory/memory.go
+++ b/storage/memory/memory.go
@@ -6,13 +6,12 @@ import (
 	"sync"
 	"time"
 
-	"github.com/sirupsen/logrus"
-
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 )
 
 // New returns an in memory storage.
-func New(logger logrus.FieldLogger) storage.Storage {
+func New(logger log.Logger) storage.Storage {
 	return &memStorage{
 		clients:         make(map[string]storage.Client),
 		authCodes:       make(map[string]storage.AuthCode),
@@ -33,7 +32,7 @@ type Config struct {
 }
 
 // Open always returns a new in memory storage.
-func (c *Config) Open(logger logrus.FieldLogger) (storage.Storage, error) {
+func (c *Config) Open(logger log.Logger) (storage.Storage, error) {
 	return New(logger), nil
 }
 
@@ -50,7 +49,7 @@ type memStorage struct {
 
 	keys storage.Keys
 
-	logger logrus.FieldLogger
+	logger log.Logger
 }
 
 type offlineSessionID struct {
diff --git a/storage/memory/memory_test.go b/storage/memory/memory_test.go
index 84a8826ef2c72753c82cb7a201c82f7415c97a26..804bd6fedf149c75abdc5bc4ecebda1086b41292 100644
--- a/storage/memory/memory_test.go
+++ b/storage/memory/memory_test.go
@@ -6,16 +6,17 @@ import (
 
 	"github.com/sirupsen/logrus"
 
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/conformance"
 )
 
 func TestStorage(t *testing.T) {
-	logger := &logrus.Logger{
+	logger := log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &logrus.TextFormatter{DisableColors: true},
 		Level:     logrus.DebugLevel,
-	}
+	})
 
 	newStorage := func() storage.Storage {
 		return New(logger)
diff --git a/storage/memory/static_test.go b/storage/memory/static_test.go
index 8513e0ee897ab597c84047bfc9376f3e2e273d8f..8ef8b2701f2524f1cfc60ff8ff165595395eb698 100644
--- a/storage/memory/static_test.go
+++ b/storage/memory/static_test.go
@@ -8,15 +8,16 @@ import (
 
 	"github.com/sirupsen/logrus"
 
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 )
 
 func TestStaticClients(t *testing.T) {
-	logger := &logrus.Logger{
+	logger := log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &logrus.TextFormatter{DisableColors: true},
 		Level:     logrus.DebugLevel,
-	}
+	})
 	backing := New(logger)
 
 	c1 := storage.Client{ID: "foo", Secret: "foo_secret"}
@@ -99,11 +100,11 @@ func TestStaticClients(t *testing.T) {
 }
 
 func TestStaticPasswords(t *testing.T) {
-	logger := &logrus.Logger{
+	logger := log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &logrus.TextFormatter{DisableColors: true},
 		Level:     logrus.DebugLevel,
-	}
+	})
 	backing := New(logger)
 
 	p1 := storage.Password{Email: "foo@example.com", Username: "foo_secret"}
@@ -211,11 +212,11 @@ func TestStaticPasswords(t *testing.T) {
 }
 
 func TestStaticConnectors(t *testing.T) {
-	logger := &logrus.Logger{
+	logger := log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &logrus.TextFormatter{DisableColors: true},
 		Level:     logrus.DebugLevel,
-	}
+	})
 	backing := New(logger)
 
 	config1 := []byte(`{"issuer": "https://accounts.google.com"}`)
diff --git a/storage/sql/config.go b/storage/sql/config.go
index 07fe6cf958ba159dc5a086d6f4e769797e828c47..8fc715b8bff21ee6ce3765636619ceaa2eb182d8 100644
--- a/storage/sql/config.go
+++ b/storage/sql/config.go
@@ -11,8 +11,8 @@ import (
 
 	"github.com/lib/pq"
 	sqlite3 "github.com/mattn/go-sqlite3"
-	"github.com/sirupsen/logrus"
 
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 )
 
@@ -28,7 +28,7 @@ type SQLite3 struct {
 }
 
 // Open creates a new storage implementation backed by SQLite3
-func (s *SQLite3) Open(logger logrus.FieldLogger) (storage.Storage, error) {
+func (s *SQLite3) Open(logger log.Logger) (storage.Storage, error) {
 	conn, err := s.open(logger)
 	if err != nil {
 		return nil, err
@@ -36,7 +36,7 @@ func (s *SQLite3) Open(logger logrus.FieldLogger) (storage.Storage, error) {
 	return conn, nil
 }
 
-func (s *SQLite3) open(logger logrus.FieldLogger) (*conn, error) {
+func (s *SQLite3) open(logger log.Logger) (*conn, error) {
 	db, err := sql.Open("sqlite3", s.File)
 	if err != nil {
 		return nil, err
@@ -99,7 +99,7 @@ type Postgres struct {
 }
 
 // Open creates a new storage implementation backed by Postgres.
-func (p *Postgres) Open(logger logrus.FieldLogger) (storage.Storage, error) {
+func (p *Postgres) Open(logger log.Logger) (storage.Storage, error) {
 	conn, err := p.open(logger, p.createDataSourceName())
 	if err != nil {
 		return nil, err
@@ -179,7 +179,7 @@ func (p *Postgres) createDataSourceName() string {
 	return strings.Join(parameters, " ")
 }
 
-func (p *Postgres) open(logger logrus.FieldLogger, dataSourceName string) (*conn, error) {
+func (p *Postgres) open(logger log.Logger, dataSourceName string) (*conn, error) {
 	db, err := sql.Open("postgres", dataSourceName)
 	if err != nil {
 		return nil, err
diff --git a/storage/sql/config_test.go b/storage/sql/config_test.go
index d823e09950da1e1f4c1687310cc1168d92c89a38..6cb52d3662d38f14100d8f0de203b9edc9cb0b99 100644
--- a/storage/sql/config_test.go
+++ b/storage/sql/config_test.go
@@ -9,6 +9,7 @@ import (
 
 	"github.com/sirupsen/logrus"
 
+	"github.com/dexidp/dex/pkg/log"
 	"github.com/dexidp/dex/storage"
 	"github.com/dexidp/dex/storage/conformance"
 )
@@ -43,11 +44,11 @@ func cleanDB(c *conn) error {
 	return err
 }
 
-var logger = &logrus.Logger{
+var logger = log.NewLogrusLogger(&logrus.Logger{
 	Out:       os.Stderr,
 	Formatter: &logrus.TextFormatter{DisableColors: true},
 	Level:     logrus.DebugLevel,
-}
+})
 
 func TestSQLite3(t *testing.T) {
 	newStorage := func() storage.Storage {
diff --git a/storage/sql/migrate_test.go b/storage/sql/migrate_test.go
index e94e819f0c2ef034babbf68ec040c0c74f444d5e..d9bfa98a32d5d195ab4390e42d95e804d526cee4 100644
--- a/storage/sql/migrate_test.go
+++ b/storage/sql/migrate_test.go
@@ -7,6 +7,8 @@ import (
 
 	sqlite3 "github.com/mattn/go-sqlite3"
 	"github.com/sirupsen/logrus"
+
+	"github.com/dexidp/dex/pkg/log"
 )
 
 func TestMigrate(t *testing.T) {
@@ -16,11 +18,11 @@ func TestMigrate(t *testing.T) {
 	}
 	defer db.Close()
 
-	logger := &logrus.Logger{
+	logger := log.NewLogrusLogger(&logrus.Logger{
 		Out:       os.Stderr,
 		Formatter: &logrus.TextFormatter{DisableColors: true},
 		Level:     logrus.DebugLevel,
-	}
+	})
 
 	errCheck := func(err error) bool {
 		sqlErr, ok := err.(sqlite3.Error)
diff --git a/storage/sql/sql.go b/storage/sql/sql.go
index dc6be4a1f4a148f3a67fbd790732ce0d45bc55c1..d27b67cef5de4dd28cfd2fb3611339871556960c 100644
--- a/storage/sql/sql.go
+++ b/storage/sql/sql.go
@@ -3,11 +3,10 @@ package sql
 
 import (
 	"database/sql"
+	"github.com/dexidp/dex/pkg/log"
 	"regexp"
 	"time"
 
-	"github.com/sirupsen/logrus"
-
 	// import third party drivers
 	_ "github.com/lib/pq"
 	_ "github.com/mattn/go-sqlite3"
@@ -113,7 +112,7 @@ func (c *conn) translateArgs(args []interface{}) []interface{} {
 type conn struct {
 	db                 *sql.DB
 	flavor             flavor
-	logger             logrus.FieldLogger
+	logger             log.Logger
 	alreadyExistsCheck func(err error) bool
 }
 
diff --git a/storage/static.go b/storage/static.go
index 5ae4f783278116392ccf59fc64875d8b7d9ce5d4..8a38385304b752891e207ff594c96b057a87c911 100644
--- a/storage/static.go
+++ b/storage/static.go
@@ -4,7 +4,7 @@ import (
 	"errors"
 	"strings"
 
-	"github.com/sirupsen/logrus"
+	"github.com/dexidp/dex/pkg/log"
 )
 
 // Tests for this code are in the "memory" package, since this package doesn't
@@ -89,11 +89,11 @@ type staticPasswordsStorage struct {
 	// A map of passwords that is indexed by lower-case email ids
 	passwordsByEmail map[string]Password
 
-	logger logrus.FieldLogger
+	logger log.Logger
 }
 
 // WithStaticPasswords returns a storage with a read-only set of passwords.
-func WithStaticPasswords(s Storage, staticPasswords []Password, logger logrus.FieldLogger) Storage {
+func WithStaticPasswords(s Storage, staticPasswords []Password, logger log.Logger) Storage {
 	passwordsByEmail := make(map[string]Password, len(staticPasswords))
 	for _, p := range staticPasswords {
 		//Enable case insensitive email comparison.