diff --git a/.example/other/test.go b/.example/other/test.go index 790580777..aa8e66f98 100644 --- a/.example/other/test.go +++ b/.example/other/test.go @@ -1,5 +1,20 @@ package main -func main() { +import ( + "github.com/gogf/gf/os/glog" + "runtime/debug" +) +func doPrintLog(content string) { + debug.PrintStack() + glog.Skip(1).Line().Println("line number with skip:", content) + glog.Line().Println("line number without skip:", content) +} + +func PrintLog(content string) { + doPrintLog(content) +} + +func main() { + PrintLog("just test") } diff --git a/debug/gdebug/gdebug_caller.go b/debug/gdebug/gdebug_caller.go index 13f7391cf..d5a55594e 100644 --- a/debug/gdebug/gdebug_caller.go +++ b/debug/gdebug/gdebug_caller.go @@ -42,12 +42,14 @@ func init() { } } -// CallerPath returns the function name and the absolute file path along with its line number of the caller. +// CallerPath returns the function name and the absolute file path along with its line +// number of the caller. func Caller(skip ...int) (function string, path string, line int) { return CallerWithFilter("", skip...) } -// CallerPathWithFilter returns the function name and the absolute file path along with its line number of the caller. +// CallerPathWithFilter returns the function name and the absolute file path along with +// its line number of the caller. // // The parameter is used to filter the path of the caller. func CallerWithFilter(filter string, skip ...int) (function string, path string, line int) { @@ -84,7 +86,10 @@ func CallerWithFilter(filter string, skip ...int) (function string, path string, return "", "", -1 } -// callerFromIndex returns the caller position and according information exclusive of the debug package. +// callerFromIndex returns the caller position and according information exclusive of the +// debug package. +// +// VERY NOTE THAT, the returned index value should be as the caller's start point. func callerFromIndex(filters []string) (pc uintptr, file string, line int, index int) { var filtered, ok bool for index = 0; index < gMAX_DEPTH; index++ { @@ -102,6 +107,9 @@ func callerFromIndex(filters []string) (pc uintptr, file string, line int, index if strings.Contains(file, gFILTER_KEY) { continue } + if index > 0 { + index-- + } return } } diff --git a/debug/gdebug/gdebug_stack.go b/debug/gdebug/gdebug_stack.go index 498f03bf2..dbfb23d22 100644 --- a/debug/gdebug/gdebug_stack.go +++ b/debug/gdebug/gdebug_stack.go @@ -35,25 +35,33 @@ func StackWithFilter(filter string, skip ...int) string { // StackWithFilters returns a formatted stack trace of the goroutine that calls it. // It calls runtime.Stack with a large enough buffer to capture the entire trace. // -// The parameter is a slice of strings, which are used to filter the path of the caller. +// The parameter is a slice of strings, which are used to filter the path of the +// caller. +// +// TODO Improve the performance using debug.Stack. func StackWithFilters(filters []string, skip ...int) string { number := 0 if len(skip) > 0 { number = skip[0] } - name := "" - space := " " - index := 1 - buffer := bytes.NewBuffer(nil) - filtered := false - ok := true - pc, file, line, start := callerFromIndex(filters) + var ( + name = "" + space = " " + index = 1 + buffer = bytes.NewBuffer(nil) + filtered = false + ok = true + pc, file, line, start = callerFromIndex(filters) + ) for i := start + number; i < gMAX_DEPTH; i++ { if i != start { pc, file, line, ok = runtime.Caller(i) } if ok { - if goRootForFilter != "" && len(file) >= len(goRootForFilter) && file[0:len(goRootForFilter)] == goRootForFilter { + // GOROOT filter. + if goRootForFilter != "" && + len(file) >= len(goRootForFilter) && + file[0:len(goRootForFilter)] == goRootForFilter { continue } filtered = false diff --git a/debug/gdebug/gdebug_z_bench_test.go b/debug/gdebug/gdebug_z_bench_test.go index 8c6dbda69..7e26cdd60 100644 --- a/debug/gdebug/gdebug_z_bench_test.go +++ b/debug/gdebug/gdebug_z_bench_test.go @@ -10,6 +10,7 @@ package gdebug import ( "runtime" + "runtime/debug" "testing" ) @@ -49,6 +50,12 @@ func Benchmark_Stack(b *testing.B) { } } +func Benchmark_StackOfStdlib(b *testing.B) { + for i := 0; i < b.N; i++ { + debug.Stack() + } +} + func Benchmark_StackWithFilter(b *testing.B) { for i := 0; i < b.N; i++ { StackWithFilter("test") diff --git a/net/gsmtp/gsmtp.go b/net/gsmtp/gsmtp.go index 91e28e386..0492b465f 100644 --- a/net/gsmtp/gsmtp.go +++ b/net/gsmtp/gsmtp.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -// Package gsmtp provides a SMTP client to access remote mail server. +// Package gsmtp provides a simple SMTP client to access remote mail server. // // Eg: // s := smtp.New("smtp.exmail.qq.com:25", "notify@a.com", "password") @@ -14,6 +14,7 @@ package gsmtp import ( "encoding/base64" "fmt" + "github.com/gogf/gf/util/gconv" "net/smtp" "strings" ) @@ -34,37 +35,45 @@ func New(address, username, password string) *SMTP { } } +var ( + // contentEncoding is the BASE64 encoding object for mail content. + contentEncoding = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") +) + // SendMail connects to the server at addr, switches to TLS if // possible, authenticates with the optional mechanism a if possible, -// and then sends an email from address from, to addresses to, with +// and then sends an email from address , to addresses , with // message msg. +// +// The parameter specifies the content type of the mail, eg: html. func (s *SMTP) SendMail(from, tos, subject, body string, contentType ...string) error { - server := "" - address := "" - - hp := strings.Split(s.Address, ":") - if (s.Address == "") || (len(hp) > 2) { - return fmt.Errorf("Server address is either empty or incorrect: %s", s.Address) + var ( + server = "" + address = "" + hp = strings.Split(s.Address, ":") + ) + if s.Address == "" || len(hp) > 2 { + return fmt.Errorf("server address is either empty or incorrect: %s", s.Address) } else if len(hp) == 1 { server = s.Address address = server + ":25" } else if len(hp) == 2 { if (hp[0] == "") || (hp[1] == "") { - return fmt.Errorf("Server address is either empty or incorrect: %s", s.Address) + return fmt.Errorf("server address is either empty or incorrect: %s", s.Address) } server = hp[0] address = s.Address } - - tosArr := []string{} - arr := strings.Split(tos, ";") + var ( + tosArr []string + arr = strings.Split(tos, ";") + ) for _, to := range arr { // TODO: replace with regex if strings.Contains(to, "@") { tosArr = append(tosArr, to) } } - if len(tosArr) == 0 { return fmt.Errorf("tos if invalid: %s", tos) } @@ -73,28 +82,27 @@ func (s *SMTP) SendMail(from, tos, subject, body string, contentType ...string) return fmt.Errorf("from is invalid: %s", from) } - b64 := base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") - - header := make(map[string]string) - header["From"] = from - header["To"] = strings.Join(tosArr, ";") - header["Subject"] = fmt.Sprintf("=?UTF-8?B?%s?=", b64.EncodeToString([]byte(subject))) - header["MIME-Version"] = "1.0" - - ct := "text/plain; charset=UTF-8" - if len(contentType) > 0 && contentType[0] == "html" { - ct = "text/html; charset=UTF-8" + header := map[string]string{ + "From": from, + "To": strings.Join(tosArr, ";"), + "Subject": fmt.Sprintf("=?UTF-8?B?%s?=", contentEncoding.EncodeToString(gconv.UnsafeStrToBytes(subject))), + "MIME-Version": "1.0", + "Content-Type": "text/plain; charset=UTF-8", + "Content-Transfer-Encoding": "base64", + } + if len(contentType) > 0 && contentType[0] == "html" { + header["Content-Type"] = "text/html; charset=UTF-8" } - - header["Content-Type"] = ct - header["Content-Transfer-Encoding"] = "base64" - message := "" for k, v := range header { message += fmt.Sprintf("%s: %s\r\n", k, v) } - message += "\r\n" + b64.EncodeToString([]byte(body)) - - auth := smtp.PlainAuth("", s.Username, s.Password, server) - return smtp.SendMail(address, auth, from, tosArr, []byte(message)) + message += "\r\n" + contentEncoding.EncodeToString(gconv.UnsafeStrToBytes(body)) + return smtp.SendMail( + address, + smtp.PlainAuth("", s.Username, s.Password, server), + from, + tosArr, + gconv.UnsafeStrToBytes(message), + ) } diff --git a/net/gsmtp/gsmtp_test.go b/net/gsmtp/gsmtp_test.go index fcd15350c..edae876ea 100644 --- a/net/gsmtp/gsmtp_test.go +++ b/net/gsmtp/gsmtp_test.go @@ -3,6 +3,7 @@ // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. + package gsmtp_test import ( diff --git a/net/gtcp/gtcp_unit_init_test.go b/net/gtcp/gtcp_unit_init_test.go index 47d002af4..974fa04db 100644 --- a/net/gtcp/gtcp_unit_init_test.go +++ b/net/gtcp/gtcp_unit_init_test.go @@ -15,7 +15,7 @@ var ( ) func init() { - for i := 9000; i <= 10000; i++ { + for i := 9000; i < 10000; i++ { ports.Append(i) } }