Skip to content

Commit 80abda2

Browse files
authored
api/log: initial implementation of the package (smallstep#859)
* api/log: initial implementation of the package * api: refactored to support api/log * scep/api: refactored to support api/log * api/log: documented the package * api: moved log-related tests to api/log
1 parent 823170e commit 80abda2

File tree

6 files changed

+111
-86
lines changed

6 files changed

+111
-86
lines changed

Diff for: api/errors.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/pkg/errors"
1010

1111
"github.com/smallstep/certificates/acme"
12+
"github.com/smallstep/certificates/api/log"
1213
"github.com/smallstep/certificates/authority/admin"
1314
"github.com/smallstep/certificates/errs"
1415
"github.com/smallstep/certificates/logging"
@@ -60,6 +61,6 @@ func WriteError(w http.ResponseWriter, err error) {
6061
}
6162

6263
if err := json.NewEncoder(w).Encode(err); err != nil {
63-
LogError(w, err)
64+
log.Error(w, err)
6465
}
6566
}

Diff for: api/log/log.go

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Package log implements API-related logging helpers.
2+
package log
3+
4+
import (
5+
"log"
6+
"net/http"
7+
8+
"github.com/smallstep/certificates/logging"
9+
)
10+
11+
// Error adds to the response writer the given error if it implements
12+
// logging.ResponseLogger. If it does not implement it, then writes the error
13+
// using the log package.
14+
func Error(rw http.ResponseWriter, err error) {
15+
if rl, ok := rw.(logging.ResponseLogger); ok {
16+
rl.WithFields(map[string]interface{}{
17+
"error": err,
18+
})
19+
} else {
20+
log.Println(err)
21+
}
22+
}
23+
24+
// EnabledResponse log the response object if it implements the EnableLogger
25+
// interface.
26+
func EnabledResponse(rw http.ResponseWriter, v interface{}) {
27+
type enableLogger interface {
28+
ToLog() (interface{}, error)
29+
}
30+
31+
if el, ok := v.(enableLogger); ok {
32+
out, err := el.ToLog()
33+
if err != nil {
34+
Error(rw, err)
35+
36+
return
37+
}
38+
39+
if rl, ok := rw.(logging.ResponseLogger); ok {
40+
rl.WithFields(map[string]interface{}{
41+
"response": out,
42+
})
43+
} else {
44+
log.Println(out)
45+
}
46+
}
47+
}

Diff for: api/log/log_test.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package log
2+
3+
import (
4+
"errors"
5+
"net/http"
6+
"net/http/httptest"
7+
"reflect"
8+
"testing"
9+
10+
"github.com/smallstep/certificates/logging"
11+
)
12+
13+
func TestError(t *testing.T) {
14+
theError := errors.New("the error")
15+
16+
type args struct {
17+
rw http.ResponseWriter
18+
err error
19+
}
20+
tests := []struct {
21+
name string
22+
args args
23+
withFields bool
24+
}{
25+
{"normalLogger", args{httptest.NewRecorder(), theError}, false},
26+
{"responseLogger", args{logging.NewResponseLogger(httptest.NewRecorder()), theError}, true},
27+
}
28+
29+
for _, tt := range tests {
30+
t.Run(tt.name, func(t *testing.T) {
31+
Error(tt.args.rw, tt.args.err)
32+
if tt.withFields {
33+
if rl, ok := tt.args.rw.(logging.ResponseLogger); ok {
34+
fields := rl.Fields()
35+
if !reflect.DeepEqual(fields["error"], theError) {
36+
t.Errorf("ResponseLogger[\"error\"] = %s, wants %s", fields["error"], theError)
37+
}
38+
} else {
39+
t.Error("ResponseWriter does not implement logging.ResponseLogger")
40+
}
41+
}
42+
})
43+
}
44+
}

Diff for: api/utils.go

+12-44
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,14 @@ package api
22

33
import (
44
"encoding/json"
5-
"log"
65
"net/http"
76

87
"google.golang.org/protobuf/encoding/protojson"
98
"google.golang.org/protobuf/proto"
109

11-
"github.com/smallstep/certificates/logging"
10+
"github.com/smallstep/certificates/api/log"
1211
)
1312

14-
// EnableLogger is an interface that enables response logging for an object.
15-
type EnableLogger interface {
16-
ToLog() (interface{}, error)
17-
}
18-
19-
// LogError adds to the response writer the given error if it implements
20-
// logging.ResponseLogger. If it does not implement it, then writes the error
21-
// using the log package.
22-
func LogError(rw http.ResponseWriter, err error) {
23-
if rl, ok := rw.(logging.ResponseLogger); ok {
24-
rl.WithFields(map[string]interface{}{
25-
"error": err,
26-
})
27-
} else {
28-
log.Println(err)
29-
}
30-
}
31-
32-
// LogEnabledResponse log the response object if it implements the EnableLogger
33-
// interface.
34-
func LogEnabledResponse(rw http.ResponseWriter, v interface{}) {
35-
if el, ok := v.(EnableLogger); ok {
36-
out, err := el.ToLog()
37-
if err != nil {
38-
LogError(rw, err)
39-
return
40-
}
41-
if rl, ok := rw.(logging.ResponseLogger); ok {
42-
rl.WithFields(map[string]interface{}{
43-
"response": out,
44-
})
45-
} else {
46-
log.Println(out)
47-
}
48-
}
49-
}
50-
5113
// JSON writes the passed value into the http.ResponseWriter.
5214
func JSON(w http.ResponseWriter, v interface{}) {
5315
JSONStatus(w, v, http.StatusOK)
@@ -59,10 +21,12 @@ func JSONStatus(w http.ResponseWriter, v interface{}, status int) {
5921
w.Header().Set("Content-Type", "application/json")
6022
w.WriteHeader(status)
6123
if err := json.NewEncoder(w).Encode(v); err != nil {
62-
LogError(w, err)
24+
log.Error(w, err)
25+
6326
return
6427
}
65-
LogEnabledResponse(w, v)
28+
29+
log.EnabledResponse(w, v)
6630
}
6731

6832
// ProtoJSON writes the passed value into the http.ResponseWriter.
@@ -78,12 +42,16 @@ func ProtoJSONStatus(w http.ResponseWriter, m proto.Message, status int) {
7842

7943
b, err := protojson.Marshal(m)
8044
if err != nil {
81-
LogError(w, err)
45+
log.Error(w, err)
46+
8247
return
8348
}
49+
8450
if _, err := w.Write(b); err != nil {
85-
LogError(w, err)
51+
log.Error(w, err)
52+
8653
return
8754
}
88-
//LogEnabledResponse(w, v)
55+
56+
// log.EnabledResponse(w, v)
8957
}

Diff for: api/utils_test.go

-35
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,11 @@ package api
33
import (
44
"net/http"
55
"net/http/httptest"
6-
"reflect"
76
"testing"
87

9-
"github.com/pkg/errors"
10-
118
"github.com/smallstep/certificates/logging"
129
)
1310

14-
func TestLogError(t *testing.T) {
15-
theError := errors.New("the error")
16-
type args struct {
17-
rw http.ResponseWriter
18-
err error
19-
}
20-
tests := []struct {
21-
name string
22-
args args
23-
withFields bool
24-
}{
25-
{"normalLogger", args{httptest.NewRecorder(), theError}, false},
26-
{"responseLogger", args{logging.NewResponseLogger(httptest.NewRecorder()), theError}, true},
27-
}
28-
29-
for _, tt := range tests {
30-
t.Run(tt.name, func(t *testing.T) {
31-
LogError(tt.args.rw, tt.args.err)
32-
if tt.withFields {
33-
if rl, ok := tt.args.rw.(logging.ResponseLogger); ok {
34-
fields := rl.Fields()
35-
if !reflect.DeepEqual(fields["error"], theError) {
36-
t.Errorf("ResponseLogger[\"error\"] = %s, wants %s", fields["error"], theError)
37-
}
38-
} else {
39-
t.Error("ResponseWriter does not implement logging.ResponseLogger")
40-
}
41-
}
42-
})
43-
}
44-
}
45-
4611
func TestJSON(t *testing.T) {
4712
type args struct {
4813
rw http.ResponseWriter

Diff for: scep/api/api.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ import (
1010
"strings"
1111

1212
"github.com/go-chi/chi"
13+
microscep "github.com/micromdm/scep/v2/scep"
14+
"github.com/pkg/errors"
15+
"go.mozilla.org/pkcs7"
16+
1317
"github.com/smallstep/certificates/api"
18+
"github.com/smallstep/certificates/api/log"
1419
"github.com/smallstep/certificates/authority/provisioner"
1520
"github.com/smallstep/certificates/scep"
16-
"go.mozilla.org/pkcs7"
17-
18-
"github.com/pkg/errors"
19-
20-
microscep "github.com/micromdm/scep/v2/scep"
2121
)
2222

2323
const (
@@ -337,7 +337,7 @@ func formatCapabilities(caps []string) []byte {
337337
func writeSCEPResponse(w http.ResponseWriter, response SCEPResponse) {
338338

339339
if response.Error != nil {
340-
api.LogError(w, response.Error)
340+
log.Error(w, response.Error)
341341
}
342342

343343
if response.Certificate != nil {

0 commit comments

Comments
 (0)