浏览代码

Merge pull request #140 from aliyun/preview_1.9.3

add sdk log level
fengyu 7 年之前
父节点
当前提交
56222d2da9
共有 5 个文件被更改,包括 210 次插入0 次删除
  1. 3 0
      oss/auth.go
  2. 19 0
      oss/client.go
  3. 81 0
      oss/client_test.go
  4. 31 0
      oss/conf.go
  5. 76 0
      oss/conn.go

+ 3 - 0
oss/auth.go

@@ -54,6 +54,9 @@ func (conn Conn) getSignedStr(req *http.Request, canonicalizedResource string) s
 	contentMd5 := req.Header.Get(HTTPHeaderContentMD5)
 
 	signStr := req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource
+
+	conn.config.WriteLog(Debug, "[Req:%p]signStr:%s.\n", req, signStr)
+
 	h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(conn.config.AccessKeySecret))
 	io.WriteString(h, signStr)
 	signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))

+ 19 - 0
oss/client.go

@@ -6,6 +6,7 @@ import (
 	"bytes"
 	"encoding/xml"
 	"io"
+	"log"
 	"net/http"
 	"strings"
 	"time"
@@ -767,6 +768,24 @@ func HTTPClient(HTTPClient *http.Client) ClientOption {
 	}
 }
 
+//
+// SetLogLevel sets the oss sdk log level
+//
+func SetLogLevel(LogLevel int) ClientOption {
+	return func(client *Client) {
+		client.Config.LogLevel = LogLevel
+	}
+}
+
+//
+// SetLogLevel sets the oss sdk log level
+//
+func SetLogger(Logger *log.Logger) ClientOption {
+	return func(client *Client) {
+		client.Config.Logger = Logger
+	}
+}
+
 // Private
 func (client Client) do(method, bucketName string, params map[string]interface{},
 	headers map[string]string, data io.Reader) (*Response, error) {

+ 81 - 0
oss/client_test.go

@@ -5,6 +5,7 @@
 package oss
 
 import (
+	"io/ioutil"
 	"log"
 	"math/rand"
 	"net/http"
@@ -1505,3 +1506,83 @@ func (s *OssClientSuite) getBucket(buckets []BucketProperties, bucket string) (b
 	}
 	return false, BucketProperties{}
 }
+
+func (s *OssClientSuite) TestHttpLogNotSignUrl(c *C) {
+	logName := "." + string(os.PathSeparator) + "test-go-sdk-httpdebug.log" + randStr(5)
+	f, err := os.OpenFile(logName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0660)
+	c.Assert(err, IsNil)
+
+	client, err := New(endpoint, accessID, accessKey)
+	client.Config.LogLevel = Debug
+
+	client.Config.Logger = log.New(f, "", log.LstdFlags)
+
+	var testBucketName = bucketNamePrefix + strings.ToLower(randStr(5))
+
+	// CreateBucket
+	err = client.CreateBucket(testBucketName)
+	f.Close()
+
+	// read log file,get http info
+	contents, err := ioutil.ReadFile(logName)
+	c.Assert(err, IsNil)
+
+	httpContent := string(contents)
+	//fmt.Println(httpContent)
+
+	c.Assert(strings.Contains(httpContent, "signStr"), Equals, true)
+	c.Assert(strings.Contains(httpContent, "Method:"), Equals, true)
+
+	// delete test bucket and log
+	os.Remove(logName)
+	client.DeleteBucket(testBucketName)
+}
+
+func (s *OssClientSuite) TestHttpLogSignUrl(c *C) {
+	logName := "." + string(os.PathSeparator) + "test-go-sdk-httpdebug-signurl.log" + randStr(5)
+	f, err := os.OpenFile(logName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0660)
+	c.Assert(err, IsNil)
+
+	client, err := New(endpoint, accessID, accessKey)
+	client.Config.LogLevel = Debug
+	client.Config.Logger = log.New(f, "", log.LstdFlags)
+
+	var testBucketName = bucketNamePrefix + strings.ToLower(randStr(5))
+
+	// CreateBucket
+	err = client.CreateBucket(testBucketName)
+	f.Close()
+
+	// clear log
+	f, err = os.OpenFile(logName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0660)
+	client.Config.Logger = log.New(f, "", log.LstdFlags)
+
+	bucket, _ := client.Bucket(testBucketName)
+	objectName := objectNamePrefix + randStr(5)
+	objectValue := randStr(20)
+
+	// Sign URL for put
+	str, err := bucket.SignURL(objectName, HTTPPut, 60)
+	c.Assert(err, IsNil)
+	c.Assert(strings.Contains(str, HTTPParamExpires+"="), Equals, true)
+	c.Assert(strings.Contains(str, HTTPParamAccessKeyID+"="), Equals, true)
+	c.Assert(strings.Contains(str, HTTPParamSignature+"="), Equals, true)
+
+	// Error put object with URL
+	err = bucket.PutObjectWithURL(str, strings.NewReader(objectValue), ContentType("image/tiff"))
+	f.Close()
+
+	// read log file,get http info
+	contents, err := ioutil.ReadFile(logName)
+	c.Assert(err, IsNil)
+
+	httpContent := string(contents)
+	//fmt.Println(httpContent)
+
+	c.Assert(strings.Contains(httpContent, "signStr"), Equals, true)
+	c.Assert(strings.Contains(httpContent, "Method:"), Equals, true)
+
+	// delete test bucket and log
+	os.Remove(logName)
+	client.DeleteBucket(testBucketName)
+}

+ 31 - 0
oss/conf.go

@@ -1,9 +1,23 @@
 package oss
 
 import (
+	"bytes"
+	"fmt"
+	"log"
+	"os"
 	"time"
 )
 
+const (
+	LogOff = iota
+	Error
+	Warn
+	Info
+	Debug
+)
+
+var LogTag = []string{"[error]", "[warn]", "[info]", "[debug]"}
+
 // HTTPTimeout defines HTTP timeout.
 type HTTPTimeout struct {
 	ConnectTimeout   time.Duration
@@ -39,6 +53,20 @@ type Config struct {
 	IsEnableMD5     bool         // Flag of enabling MD5 for upload.
 	MD5Threshold    int64        // Memory footprint threshold for each MD5 computation (16MB is the default), in byte. When the data is more than that, temp file is used.
 	IsEnableCRC     bool         // Flag of enabling CRC for upload.
+	LogLevel        int          // log level
+	Logger          *log.Logger  // For write log
+}
+
+// WriteLog
+func (config *Config) WriteLog(LogLevel int, format string, a ...interface{}) {
+	if config.LogLevel < LogLevel || config.Logger == nil {
+		return
+	}
+
+	var logBuffer bytes.Buffer
+	logBuffer.WriteString(LogTag[LogLevel-1])
+	logBuffer.WriteString(fmt.Sprintf(format, a...))
+	config.Logger.Printf("%s", logBuffer.String())
 }
 
 // getDefaultOssConfig gets the default configuration.
@@ -73,5 +101,8 @@ func getDefaultOssConfig() *Config {
 	config.IsEnableMD5 = false
 	config.IsEnableCRC = true
 
+	config.LogLevel = LogOff
+	config.Logger = log.New(os.Stdout, "", log.LstdFlags)
+
 	return &config
 }

+ 76 - 0
oss/conn.go

@@ -111,6 +111,10 @@ func (conn Conn) DoURL(method HTTPMethod, signedURL string, headers map[string]s
 	event := newProgressEvent(TransferStartedEvent, 0, req.ContentLength)
 	publishProgress(listener, event)
 
+	if conn.config.LogLevel >= Debug {
+		conn.LoggerHttpReq(req)
+	}
+
 	resp, err := conn.client.Do(req)
 	if err != nil {
 		// Transfer failed
@@ -119,6 +123,11 @@ func (conn Conn) DoURL(method HTTPMethod, signedURL string, headers map[string]s
 		return nil, err
 	}
 
+	if conn.config.LogLevel >= Debug {
+		//print out http resp
+		conn.LoggerHttpResp(req, resp)
+	}
+
 	// Transfer completed
 	event = newProgressEvent(TransferCompletedEvent, tracker.completedBytes, req.ContentLength)
 	publishProgress(listener, event)
@@ -231,7 +240,12 @@ func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource st
 	event := newProgressEvent(TransferStartedEvent, 0, req.ContentLength)
 	publishProgress(listener, event)
 
+	if conn.config.LogLevel >= Debug {
+		conn.LoggerHttpReq(req)
+	}
+
 	resp, err := conn.client.Do(req)
+
 	if err != nil {
 		// Transfer failed
 		event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength)
@@ -239,6 +253,11 @@ func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource st
 		return nil, err
 	}
 
+	if conn.config.LogLevel >= Debug {
+		//print out http resp
+		conn.LoggerHttpResp(req, resp)
+	}
+
 	// Transfer completed
 	event = newProgressEvent(TransferCompletedEvent, tracker.completedBytes, req.ContentLength)
 	publishProgress(listener, event)
@@ -395,6 +414,63 @@ func (conn Conn) handleResponse(resp *http.Response, crc hash.Hash64) (*Response
 	}, nil
 }
 
+func (conn Conn) LoggerHttpReq(req *http.Request) {
+	var logBuffer bytes.Buffer
+	logBuffer.WriteString(fmt.Sprintf("[Req:%p]Method:%s,", req, req.Method))
+	logBuffer.WriteString(fmt.Sprintf("Host:%s,", req.URL.Host))
+	logBuffer.WriteString(fmt.Sprintf("Path:%s,", req.URL.Path))
+	logBuffer.WriteString(fmt.Sprintf("Query:%s,", req.URL.RawQuery))
+	logBuffer.WriteString(fmt.Sprintf("Header info:"))
+
+	for k, v := range req.Header {
+		var valueBuffer bytes.Buffer
+		for j := 0; j < len(v); j++ {
+			if j > 0 {
+				valueBuffer.WriteString(" ")
+			}
+			valueBuffer.WriteString(v[j])
+		}
+		logBuffer.WriteString(fmt.Sprintf("%s:%s,", k, valueBuffer.String()))
+	}
+	conn.config.WriteLog(Debug, "%s.\n", logBuffer.String())
+}
+
+func (conn Conn) LoggerHttpResp(req *http.Request, resp *http.Response) {
+	var logBuffer bytes.Buffer
+	logBuffer.WriteString(fmt.Sprintf("[Resp:%p]StatusCode:%d,", req, resp.StatusCode))
+	logBuffer.WriteString(fmt.Sprintf("Header info:"))
+	for k, v := range resp.Header {
+		var valueBuffer bytes.Buffer
+		for j := 0; j < len(v); j++ {
+			if j > 0 {
+				valueBuffer.WriteString(" ")
+			}
+			valueBuffer.WriteString(v[j])
+		}
+		logBuffer.WriteString(fmt.Sprintf("%s:%s,", k, valueBuffer.String()))
+	}
+
+	statusCode := resp.StatusCode
+	if statusCode >= 400 && statusCode <= 505 {
+		// 4xx and 5xx indicate that the operation has error occurred
+		var respBody []byte
+		respBody, err := readResponseBody(resp)
+		if err != nil {
+			return
+		}
+
+		if len(respBody) == 0 {
+			// No error in response body
+		} else {
+			// Response contains storage service error object, unmarshal
+			logBuffer.WriteString(fmt.Sprintf("Body:%s", string(respBody)))
+		}
+	} else if statusCode >= 300 && statusCode <= 307 {
+		// OSS use 3xx, but response has no body
+	}
+	conn.config.WriteLog(Debug, "%s.\n", logBuffer.String())
+}
+
 func calcMD5(body io.Reader, contentLen, md5Threshold int64) (reader io.Reader, b64 string, tempFile *os.File, err error) {
 	if contentLen == 0 || contentLen > md5Threshold {
 		// Huge body, use temporary file