Skip to content

Commit

Permalink
Extract logger
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolai86 committed Jun 20, 2016
1 parent 94837cf commit bd4dda3
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 106 deletions.
149 changes: 46 additions & 103 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ import (
"text/tabwriter"
"text/template"
"time"

log "github.com/Sirupsen/logrus"
"github.com/moul/anonuuid"
"github.com/moul/http2curl"
)

// Default values
Expand Down Expand Up @@ -68,9 +64,11 @@ type ScalewayAPI struct {
// Cache is used to quickly resolve identifiers from names
Cache *ScalewayCache

client *http.Client
anonuuid anonuuid.AnonUUID
verbose bool
client *http.Client
verbose bool

//
Logger Logger
}

// ScalewayAPIError represents a Scaleway API Error
Expand All @@ -93,30 +91,31 @@ type ScalewayAPIError struct {

// Error returns a string representing the error
func (e ScalewayAPIError) Error() string {
if e.Message != "" {
return e.Message
}
if e.APIMessage != "" {
return e.APIMessage
}
if e.StatusCode != 0 {
return fmt.Sprintf("Invalid return code, got %d", e.StatusCode)
}
panic(e)
}

// Debug create a debug log entry with HTTP error informations
func (e ScalewayAPIError) Debug() {
log.WithFields(log.Fields{
var b bytes.Buffer
for k, v := range map[string]interface{}{
"StatusCode": e.StatusCode,
"Type": e.Type,
"Message": e.Message,
}).Debug(e.APIMessage)
"APIMessage": e.APIMessage,
} {
fmt.Fprintf(&b, " %-30s %s", fmt.Sprintf("%s: ", k), v)
}
return b.String()
}

// error.Fields handling
for k, v := range e.Fields {
log.Debugf(" %-30s %s", fmt.Sprintf("%s: ", k), v)
// HideAPICredentials removes API credentials from a string
func (s *ScalewayAPI) HideAPICredentials(input string) string {
output := input
if s.Token != "" {
output = strings.Replace(output, s.Token, "00000000-0000-4000-8000-000000000000", -1)
}
if s.Organization != "" {
output = strings.Replace(output, s.Organization, "00000000-0000-5000-9000-000000000000", -1)
}
if s.password != "" {
output = strings.Replace(output, s.password, "XX-XX-XX-XX", -1)
}
return output
}

// ScalewayIPAddress represents a Scaleway IP address
Expand Down Expand Up @@ -832,7 +831,7 @@ type MarketImages struct {
}

// NewScalewayAPI creates a ready-to-use ScalewayAPI client
func NewScalewayAPI(organization, token, userAgent string) (*ScalewayAPI, error) {
func NewScalewayAPI(organization, token, userAgent string, options ...func(*ScalewayAPI)) (*ScalewayAPI, error) {
cache, err := NewScalewayCache()
if err != nil {
return nil, err
Expand All @@ -842,13 +841,17 @@ func NewScalewayAPI(organization, token, userAgent string) (*ScalewayAPI, error)
Organization: organization,
Token: token,
Cache: cache,
Logger: NewDefaultLogger(),
verbose: os.Getenv("SCW_VERBOSE_API") != "",
password: "",
userAgent: userAgent,

// internal
anonuuid: *anonuuid.New(),
client: &http.Client{},
client: &http.Client{},
}

for _, option := range options {
option(s)
}

if os.Getenv("SCW_TLSVERIFY") == "0" {
Expand Down Expand Up @@ -882,15 +885,8 @@ func (s *ScalewayAPI) GetResponse(apiURL, resource string) (*http.Response, erro
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", s.userAgent)

curl, err := http2curl.GetCurlCommand(req)
if err != nil {
return nil, err
}
if os.Getenv("SCW_SENSITIVE") != "1" {
log.Debug(s.HideAPICredentials(curl.String()))
} else {
log.Debug(curl.String())
}
s.Logger.LogHTTP(req)

return s.client.Do(req)
}

Expand All @@ -911,15 +907,7 @@ func (s *ScalewayAPI) PostResponse(apiURL, resource string, data interface{}) (*
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", s.userAgent)

curl, err := http2curl.GetCurlCommand(req)
if err != nil {
return nil, err
}
if os.Getenv("SCW_SENSITIVE") != "1" {
log.Debug(s.HideAPICredentials(curl.String()))
} else {
log.Debug(curl.String())
}
s.Logger.LogHTTP(req)

return s.client.Do(req)
}
Expand All @@ -941,15 +929,7 @@ func (s *ScalewayAPI) PatchResponse(apiURL, resource string, data interface{}) (
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", s.userAgent)

curl, err := http2curl.GetCurlCommand(req)
if err != nil {
return nil, err
}
if os.Getenv("SCW_SENSITIVE") != "1" {
log.Debug(s.HideAPICredentials(curl.String()))
} else {
log.Debug(curl.String())
}
s.Logger.LogHTTP(req)

return s.client.Do(req)
}
Expand All @@ -971,15 +951,7 @@ func (s *ScalewayAPI) PutResponse(apiURL, resource string, data interface{}) (*h
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", s.userAgent)

curl, err := http2curl.GetCurlCommand(req)
if err != nil {
return nil, err
}
if os.Getenv("SCW_SENSITIVE") != "1" {
log.Debug(s.HideAPICredentials(curl.String()))
} else {
log.Debug(curl.String())
}
s.Logger.LogHTTP(req)

return s.client.Do(req)
}
Expand All @@ -996,15 +968,7 @@ func (s *ScalewayAPI) DeleteResponse(apiURL, resource string) (*http.Response, e
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", s.userAgent)

curl, err := http2curl.GetCurlCommand(req)
if err != nil {
return nil, err
}
if os.Getenv("SCW_SENSITIVE") != "1" {
log.Debug(s.HideAPICredentials(curl.String()))
} else {
log.Debug(curl.String())
}
s.Logger.LogHTTP(req)

return s.client.Do(req)
}
Expand Down Expand Up @@ -1032,17 +996,17 @@ func (s *ScalewayAPI) handleHTTPError(goodStatusCode []int, resp *http.Response)
return nil, err
}
scwError.StatusCode = resp.StatusCode
scwError.Debug()
s.Logger.Log(scwError.Error())
return nil, scwError
}
if s.verbose {
var js bytes.Buffer

err = json.Indent(&js, body, "", " ")
if err != nil {
log.Debug(string(body))
s.Logger.Log(string(body))
} else {
log.Debug(js.String())
s.Logger.Log(js.String())
}
}
return body, nil
Expand All @@ -1069,12 +1033,11 @@ func (s *ScalewayAPI) GetServers(all bool, limit int) (*[]ScalewayServer, error)
return nil, err
}

var servers ScalewayServers

body, err := s.handleHTTPError([]int{200}, resp)
if err != nil {
return nil, err
}
var servers ScalewayServers
if err = json.Unmarshal(body, &servers); err != nil {
return nil, err
}
Expand Down Expand Up @@ -1708,8 +1671,6 @@ func (s *ScalewayUserdata) String() string {

// GetUserdata gets a specific userdata for a server
func (s *ScalewayAPI) GetUserdata(serverID, key string, metadata bool) (*ScalewayUserdata, error) {
var data ScalewayUserdata
var err error
var url, endpoint string

endpoint = ComputeAPI
Expand All @@ -1720,6 +1681,7 @@ func (s *ScalewayAPI) GetUserdata(serverID, key string, metadata bool) (*Scalewa
url = fmt.Sprintf("servers/%s/user_data/%s", serverID, key)
}

var err error
resp, err := s.GetResponse(endpoint, url)
if resp != nil {
defer resp.Body.Close()
Expand All @@ -1731,6 +1693,7 @@ func (s *ScalewayAPI) GetUserdata(serverID, key string, metadata bool) (*Scalewa
if resp.StatusCode != 200 {
return nil, fmt.Errorf("no such user_data %q (%d)", key, resp.StatusCode)
}
var data ScalewayUserdata
data, err = ioutil.ReadAll(resp.Body)
return &data, err
}
Expand Down Expand Up @@ -1760,12 +1723,7 @@ func (s *ScalewayAPI) PatchUserdata(serverID, key string, value []byte, metadata
req.Header.Set("Content-Type", "text/plain")
req.Header.Set("User-Agent", s.userAgent)

curl, err := http2curl.GetCurlCommand(req)
if os.Getenv("SCW_SENSITIVE") != "1" {
log.Debug(s.HideAPICredentials(curl.String()))
} else {
log.Debug(curl.String())
}
s.Logger.LogHTTP(req)

resp, err := s.client.Do(req)
if resp != nil {
Expand Down Expand Up @@ -2420,7 +2378,7 @@ func (s *ScalewayAPI) GetQuotas() (*ScalewayGetQuotas, error) {
// GetBootscriptID returns exactly one bootscript matching
func (s *ScalewayAPI) GetBootscriptID(needle, arch string) (string, error) {
// Parses optional type prefix, i.e: "bootscript:name" -> "name"
if anonuuid.IsUUID(needle) == nil {
if len(strings.Split(needle, ":")) == 1 {
return needle, nil
}

Expand All @@ -2440,21 +2398,6 @@ func (s *ScalewayAPI) GetBootscriptID(needle, arch string) (string, error) {
return "", showResolverResults(needle, bootscripts)
}

// HideAPICredentials removes API credentials from a string
func (s *ScalewayAPI) HideAPICredentials(input string) string {
output := input
if s.Token != "" {
output = strings.Replace(output, s.Token, s.anonuuid.FakeUUID(s.Token), -1)
}
if s.Organization != "" {
output = strings.Replace(output, s.Organization, s.anonuuid.FakeUUID(s.Organization), -1)
}
if s.password != "" {
output = strings.Replace(output, s.password, "XX-XX-XX-XX", -1)
}
return output
}

func rootNetDial(network, addr string) (net.Conn, error) {
dialer := net.Dialer{
Timeout: 10 * time.Second,
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ func TestNewScalewayAPI(t *testing.T) {
So(api.Organization, ShouldEqual, "my-organization")
So(api.Cache, ShouldNotBeNil)
So(api.client, ShouldNotBeNil)
So(api.anonuuid, ShouldNotBeNil)
So(api.Logger, ShouldNotBeNil)
})
}
36 changes: 36 additions & 0 deletions pkg/api/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (C) 2015 Scaleway. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.md file.

package api

import (
"log"
"net/http"
"os"
)

// Logger handles logging concerns for the Scaleway API SDK
type Logger interface {
LogHTTP(*http.Request)
Log(...interface{})
}

// NewDefaultLogger returns a logger which is configured for stdout
func NewDefaultLogger() Logger {
return &defaultLogger{
logger: log.New(os.Stdout, "", log.LstdFlags),
}
}

type defaultLogger struct {
logger *log.Logger
}

func (l defaultLogger) LogHTTP(r *http.Request) {
l.logger.Printf("%s %s", r.Method, r.URL.RawPath)
}

func (l defaultLogger) Log(args ...interface{}) {
l.logger.Println(args...)
}
35 changes: 33 additions & 2 deletions pkg/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import (

"github.com/Sirupsen/logrus"
flag "github.com/docker/docker/pkg/mflag"
"github.com/hashicorp/go-version"
"github.com/moul/http2curl"

version "github.com/hashicorp/go-version"
"github.com/scaleway/scaleway-cli/pkg/api"
"github.com/scaleway/scaleway-cli/pkg/commands"
"github.com/scaleway/scaleway-cli/pkg/config"
Expand Down Expand Up @@ -140,7 +141,37 @@ func getScalewayAPI() (*api.ScalewayAPI, error) {
if err != nil {
return nil, err
}
return api.NewScalewayAPI(config.Organization, config.Token, scwversion.UserAgent())
return api.NewScalewayAPI(config.Organization, config.Token, scwversion.UserAgent(), func(s *api.ScalewayAPI) {
s.Logger = newCliLogger(s)
})
}

type cliLogger struct {
logrus.Logger
s *api.ScalewayAPI
}

func (l *cliLogger) Log(args ...interface{}) {
l.Log(args...)
}

func (l cliLogger) LogHTTP(req *http.Request) {
curl, err := http2curl.GetCurlCommand(req)
if err != nil {
l.Fatalf("Failed to convert to curl request: %q", err)
}

if os.Getenv("SCW_SENSITIVE") != "1" {
l.Debug(l.s.HideAPICredentials(curl.String()))
} else {
l.Debug(curl.String())
}
}

func newCliLogger(s *api.ScalewayAPI) api.Logger {
return &cliLogger{
s: s,
}
}

func initLogging(debug bool, verbose bool, streams *commands.Streams) {
Expand Down

0 comments on commit bd4dda3

Please sign in to comment.