Skip to content

Commit 356f0d5

Browse files
authored
Add debug log feature (#58)
1 parent e84d29b commit 356f0d5

File tree

15 files changed

+444
-48
lines changed

15 files changed

+444
-48
lines changed

README.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ After initial setup or when the token has been expired, just run:
3333

3434
```
3535
% kubelogin
36-
2019/04/09 13:33:37 Using current-context: hello.k8s.local
37-
2019/04/09 13:33:38 Open http://localhost:8000 for authorization
38-
2019/04/09 13:33:44 Got a token for subject=1234567890
39-
2019/04/09 13:33:44 Updated .kubeconfig
36+
Using current-context: hello.k8s.local
37+
Open http://localhost:8000 for authorization
38+
Got a token for subject 0123456789 (valid until 2019-04-12 11:00:49 +0900 JST)
39+
Updated ~/.kube/config
4040
```
4141

4242
or run as a kubectl plugin:
@@ -68,6 +68,7 @@ Application Options:
6868
--insecure-skip-tls-verify If set, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
6969
[$KUBELOGIN_INSECURE_SKIP_TLS_VERIFY]
7070
--skip-open-browser If set, it does not open the browser on authentication. [$KUBELOGIN_SKIP_OPEN_BROWSER]
71+
-v, --v= If set to 1 or greater, show debug log (default: 0)
7172
7273
Help Options:
7374
-h, --help Show this help message

adaptors/cmd.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,17 @@ func (cmd *Cmd) Run(ctx context.Context, args []string, version string) int {
3030
version)
3131
args, err := parser.ParseArgs(args[1:])
3232
if err != nil {
33-
cmd.Logger.Logf("Error: %s", err)
33+
cmd.Logger.Printf("Error: %s", err)
3434
return 1
3535
}
3636
if len(args) > 0 {
37-
cmd.Logger.Logf("Error: too many arguments")
37+
cmd.Logger.Printf("Error: too many arguments")
3838
return 1
3939
}
40+
cmd.Logger.SetLevel(adaptors.LogLevel(o.Verbose))
4041
kubeConfig, err := o.ExpandKubeConfig()
4142
if err != nil {
42-
cmd.Logger.Logf("Error: invalid option: %s", err)
43+
cmd.Logger.Printf("Error: invalid option: %s", err)
4344
return 1
4445
}
4546

@@ -50,7 +51,7 @@ func (cmd *Cmd) Run(ctx context.Context, args []string, version string) int {
5051
SkipOpenBrowser: o.SkipOpenBrowser,
5152
}
5253
if err := cmd.Login.Do(ctx, in); err != nil {
53-
cmd.Logger.Logf("Error: %s", err)
54+
cmd.Logger.Printf("Error: %s", err)
5455
return 1
5556
}
5657
return 0
@@ -61,6 +62,7 @@ type cmdOptions struct {
6162
ListenPort int `long:"listen-port" default:"8000" env:"KUBELOGIN_LISTEN_PORT" description:"Port used by kubelogin to bind its webserver"`
6263
SkipTLSVerify bool `long:"insecure-skip-tls-verify" env:"KUBELOGIN_INSECURE_SKIP_TLS_VERIFY" description:"If set, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure"`
6364
SkipOpenBrowser bool `long:"skip-open-browser" env:"KUBELOGIN_SKIP_OPEN_BROWSER" description:"If set, it does not open the browser on authentication."`
65+
Verbose int `long:"v" short:"v" default:"0" description:"If set to 1 or greater, show debug log"`
6466
}
6567

6668
// ExpandKubeConfig returns an expanded KubeConfig path.

adaptors/cmd_test.go

+14-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"testing"
66

77
"github.com/golang/mock/gomock"
8+
"github.com/int128/kubelogin/adaptors/interfaces"
9+
"github.com/int128/kubelogin/adaptors/mock_adaptors"
810
"github.com/int128/kubelogin/usecases/interfaces"
911
"github.com/int128/kubelogin/usecases/mock_usecases"
1012
"github.com/mitchellh/go-homedir"
@@ -26,9 +28,13 @@ func TestCmd_Run(t *testing.T) {
2628
ListenPort: 8000,
2729
})
2830

31+
logger := mock_adaptors.NewLogger(t, ctrl)
32+
logger.EXPECT().
33+
SetLevel(adaptors.LogLevel(0))
34+
2935
cmd := Cmd{
3036
Login: login,
31-
Logger: t,
37+
Logger: logger,
3238
}
3339
exitCode := cmd.Run(ctx, []string{executable}, version)
3440
if exitCode != 0 {
@@ -50,14 +56,19 @@ func TestCmd_Run(t *testing.T) {
5056
SkipOpenBrowser: true,
5157
})
5258

59+
logger := mock_adaptors.NewLogger(t, ctrl)
60+
logger.EXPECT().
61+
SetLevel(adaptors.LogLevel(1))
62+
5363
cmd := Cmd{
5464
Login: login,
55-
Logger: t,
65+
Logger: logger,
5666
}
5767
exitCode := cmd.Run(ctx, []string{executable,
5868
"--listen-port", "10080",
5969
"--insecure-skip-tls-verify",
6070
"--skip-open-browser",
71+
"-v1",
6172
}, version)
6273
if exitCode != 0 {
6374
t.Errorf("exitCode wants 0 but %d", exitCode)
@@ -69,7 +80,7 @@ func TestCmd_Run(t *testing.T) {
6980
defer ctrl.Finish()
7081
cmd := Cmd{
7182
Login: mock_usecases.NewMockLogin(ctrl),
72-
Logger: t,
83+
Logger: mock_adaptors.NewLogger(t, ctrl),
7384
}
7485
exitCode := cmd.Run(context.TODO(), []string{executable, "some"}, version)
7586
if exitCode != 1 {

adaptors/http.go

+15-7
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,34 @@ import (
88
"net/http"
99

1010
"github.com/int128/kubelogin/adaptors/interfaces"
11+
"github.com/int128/kubelogin/infrastructure"
1112
"github.com/pkg/errors"
13+
"go.uber.org/dig"
1214
)
1315

14-
func NewHTTP() adaptors.HTTP {
15-
return &HTTP{}
16+
func NewHTTP(i HTTP) adaptors.HTTP {
17+
return &i
1618
}
1719

18-
type HTTP struct{}
20+
type HTTP struct {
21+
dig.In
22+
Logger adaptors.Logger
23+
}
1924

2025
func (*HTTP) NewClientConfig() adaptors.HTTPClientConfig {
2126
return &httpClientConfig{
2227
certPool: x509.NewCertPool(),
2328
}
2429
}
2530

26-
func (*HTTP) NewClient(config adaptors.HTTPClientConfig) (*http.Client, error) {
31+
func (h *HTTP) NewClient(config adaptors.HTTPClientConfig) (*http.Client, error) {
2732
return &http.Client{
28-
Transport: &http.Transport{
29-
TLSClientConfig: config.TLSConfig(),
30-
Proxy: http.ProxyFromEnvironment,
33+
Transport: &infrastructure.LoggingTransport{
34+
Base: &http.Transport{
35+
TLSClientConfig: config.TLSConfig(),
36+
Proxy: http.ProxyFromEnvironment,
37+
},
38+
Logger: h.Logger,
3139
},
3240
}, nil
3341
}

adaptors/interfaces/adaptors.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"k8s.io/client-go/tools/clientcmd/api"
1010
)
1111

12-
//go:generate mockgen -package mock_adaptors -destination ../mock_adaptors/mock_adaptors.go github.com/int128/kubelogin/adaptors/interfaces KubeConfig,HTTP,HTTPClientConfig,OIDC
12+
//go:generate mockgen -package mock_adaptors -destination ../mock_adaptors/mock_adaptors.go github.com/int128/kubelogin/adaptors/interfaces KubeConfig,HTTP,HTTPClientConfig,OIDC,Logger
1313

1414
type Cmd interface {
1515
Run(ctx context.Context, args []string, version string) int
@@ -66,5 +66,17 @@ type OIDCVerifyTokenIn struct {
6666
}
6767

6868
type Logger interface {
69-
Logf(format string, v ...interface{})
69+
Printf(format string, v ...interface{})
70+
Debugf(level LogLevel, format string, v ...interface{})
71+
SetLevel(level LogLevel)
72+
IsEnabled(level LogLevel) bool
7073
}
74+
75+
// LogLevel represents a log level for debug.
76+
//
77+
// 0 = None
78+
// 1 = Including in/out
79+
// 2 = Including transport headers
80+
// 3 = Including transport body
81+
//
82+
type LogLevel int

adaptors/logger.go

+36-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,48 @@ package adaptors
22

33
import (
44
"log"
5+
"os"
56

67
"github.com/int128/kubelogin/adaptors/interfaces"
78
)
89

10+
// NewLogger returns a Logger with the standard log.Logger for messages and debug.
911
func NewLogger() adaptors.Logger {
10-
return &Logger{}
12+
return &Logger{
13+
stdLogger: log.New(os.Stderr, "", 0),
14+
debugLogger: log.New(os.Stderr, "", log.Ltime|log.Lmicroseconds),
15+
}
1116
}
1217

13-
type Logger struct{}
18+
// NewLoggerWith returns a Logger with the given standard log.Logger.
19+
func NewLoggerWith(l stdLogger) *Logger {
20+
return &Logger{
21+
stdLogger: l,
22+
debugLogger: l,
23+
}
24+
}
25+
26+
type stdLogger interface {
27+
Printf(format string, v ...interface{})
28+
}
29+
30+
// Logger wraps the standard log.Logger and just provides debug level.
31+
type Logger struct {
32+
stdLogger
33+
debugLogger stdLogger
34+
level adaptors.LogLevel
35+
}
36+
37+
func (l *Logger) Debugf(level adaptors.LogLevel, format string, v ...interface{}) {
38+
if l.IsEnabled(level) {
39+
l.debugLogger.Printf(format, v...)
40+
}
41+
}
42+
43+
func (l *Logger) SetLevel(level adaptors.LogLevel) {
44+
l.level = level
45+
}
1446

15-
func (*Logger) Logf(format string, v ...interface{}) {
16-
log.Printf(format, v...)
47+
func (l *Logger) IsEnabled(level adaptors.LogLevel) bool {
48+
return level <= l.level
1749
}

adaptors/logger_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package adaptors
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/int128/kubelogin/adaptors/interfaces"
8+
)
9+
10+
type mockStdLogger struct {
11+
count int
12+
}
13+
14+
func (l *mockStdLogger) Printf(format string, v ...interface{}) {
15+
l.count++
16+
}
17+
18+
func TestLogger_Debugf(t *testing.T) {
19+
for _, c := range []struct {
20+
loggerLevel adaptors.LogLevel
21+
debugfLevel adaptors.LogLevel
22+
count int
23+
}{
24+
{0, 0, 1},
25+
{0, 1, 0},
26+
27+
{1, 0, 1},
28+
{1, 1, 1},
29+
{1, 2, 0},
30+
31+
{2, 1, 1},
32+
{2, 2, 1},
33+
{2, 3, 0},
34+
} {
35+
t.Run(fmt.Sprintf("%+v", c), func(t *testing.T) {
36+
m := &mockStdLogger{}
37+
l := &Logger{debugLogger: m, level: c.loggerLevel}
38+
l.Debugf(c.debugfLevel, "hello")
39+
if m.count != c.count {
40+
t.Errorf("count wants %d but %d", c.count, m.count)
41+
}
42+
})
43+
}
44+
}
45+
46+
func TestLogger_Printf(t *testing.T) {
47+
m := &mockStdLogger{}
48+
l := &Logger{stdLogger: m}
49+
l.Printf("hello")
50+
if m.count != 1 {
51+
t.Errorf("count wants %d but %d", 1, m.count)
52+
}
53+
}

adaptors/mock_adaptors/logger.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package mock_adaptors
2+
3+
import (
4+
"github.com/golang/mock/gomock"
5+
"github.com/int128/kubelogin/adaptors/interfaces"
6+
)
7+
8+
func NewLogger(t testingLogger, ctrl *gomock.Controller) *Logger {
9+
return &Logger{
10+
MockLogger: NewMockLogger(ctrl),
11+
testingLogger: t,
12+
}
13+
}
14+
15+
type testingLogger interface {
16+
Logf(format string, v ...interface{})
17+
}
18+
19+
// Logger provides mock feature but overrides output methods with actual logging.
20+
type Logger struct {
21+
*MockLogger
22+
testingLogger testingLogger
23+
}
24+
25+
func (l *Logger) Printf(format string, v ...interface{}) {
26+
l.testingLogger.Logf(format, v...)
27+
}
28+
29+
func (l *Logger) Debugf(level adaptors.LogLevel, format string, v ...interface{}) {
30+
l.testingLogger.Logf(format, v...)
31+
}

0 commit comments

Comments
 (0)