Skip to content

Commit

Permalink
feat: add strings and sql log. (#24)
Browse files Browse the repository at this point in the history
* optimization: slice sub.

* fix: rpc logger add more detail info.

* feat: add msg gateway error.

* refactor: separate functions with error containing message and error with only stack trace.

* feat: add stdout and stderr info.

* feat: add strings and sql log.
  • Loading branch information
FGadvancer authored Mar 19, 2024
1 parent eab6641 commit 0edcd3c
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 9 deletions.
8 changes: 4 additions & 4 deletions a2r/api2rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ func Call[A, B, C any](rpc func(client C, ctx context.Context, req *A, options .
var req A
if err := c.BindJSON(&req); err != nil {
log.ZWarn(c, "gin bind json error", err, "req", req)
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) // 参数错误
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) //args error
return
}
if err := checker.Validate(&req); err != nil {
apiresp.GinError(c, err) // 参数校验失败
apiresp.GinError(c, err) // args validate error
return
}
data, err := rpc(client, c, &req)
if err != nil {
apiresp.GinError(c, err) // RPC调用失败
apiresp.GinError(c, err) // rpc call failed
return
}
apiresp.GinSuccess(c, data) // 成功
apiresp.GinSuccess(c, data) // rpc call success
}
3 changes: 2 additions & 1 deletion errs/coderr.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ type CodeError interface {
Msg() string
Detail() string
WithDetail(detail string) CodeError
// Is 判断是否是某个错误, loose为false时, 只有错误码相同就认为是同一个错误, 默认为true
// Is checks if the error is of a certain type, when loose is false,
//only the error code is the same is considered the same error, default is true
Is(err error, loose ...bool) bool
Wrap() error
WrapMsg(msg string, kv ...any) error
Expand Down
8 changes: 4 additions & 4 deletions errs/predefine.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ var (
ErrData = NewCodeError(DataError, "DataError")
ErrTokenExpired = NewCodeError(TokenExpiredError, "TokenExpiredError")
ErrTokenInvalid = NewCodeError(TokenInvalidError, "TokenInvalidError") //
ErrTokenMalformed = NewCodeError(TokenMalformedError, "TokenMalformedError") // 格式错误
ErrTokenNotValidYet = NewCodeError(TokenNotValidYetError, "TokenNotValidYetError") // 还未生效
ErrTokenUnknown = NewCodeError(TokenUnknownError, "TokenUnknownError") // 未知错误
ErrTokenMalformed = NewCodeError(TokenMalformedError, "TokenMalformedError") //
ErrTokenNotValidYet = NewCodeError(TokenNotValidYetError, "TokenNotValidYetError") //
ErrTokenUnknown = NewCodeError(TokenUnknownError, "TokenUnknownError") //
ErrTokenKicked = NewCodeError(TokenKickedError, "TokenKickedError")
ErrTokenNotExist = NewCodeError(TokenNotExistError, "TokenNotExistError") // 在redis中不存在
ErrTokenNotExist = NewCodeError(TokenNotExistError, "TokenNotExistError") //
ErrDuplicateKey = NewCodeError(DuplicateKeyError, "DuplicateKeyError")

ErrMessageHasReadDisable = NewCodeError(MessageHasReadDisable, "MessageHasReadDisable")
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
go.mongodb.org/mongo-driver v1.12.0
go.uber.org/zap v1.24.0
google.golang.org/grpc v1.56.2
gorm.io/gorm v1.25.8
)

require (
Expand All @@ -32,6 +33,8 @@ require (
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
Expand Down Expand Up @@ -251,4 +255,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.25.8 h1:WAGEZ/aEcznN4D03laj8DKnehe1e9gYQAjW8xyPRdeo=
gorm.io/gorm v1.25.8/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
89 changes: 89 additions & 0 deletions log/sql_logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package log

import (
"context"
"fmt"
"time"

"github.com/pkg/errors"
"gorm.io/gorm"
gormLogger "gorm.io/gorm/logger"
gormUtils "gorm.io/gorm/utils"
)

type SqlLogger struct {
LogLevel gormLogger.LogLevel
IgnoreRecordNotFoundError bool
SlowThreshold time.Duration
}

func NewSqlLogger(logLevel gormLogger.LogLevel, ignoreRecordNotFoundError bool, slowThreshold time.Duration) *SqlLogger {
return &SqlLogger{
LogLevel: logLevel,
IgnoreRecordNotFoundError: ignoreRecordNotFoundError,
SlowThreshold: slowThreshold,
}
}

func (l *SqlLogger) LogMode(logLevel gormLogger.LogLevel) gormLogger.Interface {
newLogger := *l
newLogger.LogLevel = logLevel
return &newLogger
}

func (SqlLogger) Info(ctx context.Context, msg string, args ...interface{}) {
ZInfo(ctx, msg, args)
}

func (SqlLogger) Warn(ctx context.Context, msg string, args ...interface{}) {
ZWarn(ctx, msg, nil, args)
}

func (SqlLogger) Error(ctx context.Context, msg string, args ...interface{}) {
ZError(ctx, msg, nil, args)
}

func (l *SqlLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
if l.LogLevel <= gormLogger.Silent {
return
}
elapsed := time.Since(begin)
switch {
case err != nil && l.LogLevel >= gormLogger.Error && (!errors.Is(err, gorm.ErrRecordNotFound) || !l.IgnoreRecordNotFoundError):
sql, rows := fc()
if rows == -1 {
ZError(ctx, "sql exec detail", err, "gorm", gormUtils.FileWithLineNum(), "elapsed time", fmt.Sprintf("%f(ms)", float64(elapsed.Nanoseconds())/1e6), "sql", sql)
} else {
ZError(ctx, "sql exec detail", err, "gorm", gormUtils.FileWithLineNum(), "elapsed time", fmt.Sprintf("%f(ms)", float64(elapsed.Nanoseconds())/1e6), "rows", rows, "sql", sql)
}
case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= gormLogger.Warn:
sql, rows := fc()
slowLog := fmt.Sprintf("SLOW SQL >= %v", l.SlowThreshold)
if rows == -1 {
ZWarn(ctx, "sql exec detail", nil, "gorm", gormUtils.FileWithLineNum(), "slow sql", slowLog, "elapsed time", fmt.Sprintf("%f(ms)", float64(elapsed.Nanoseconds())/1e6), "sql", sql)
} else {
ZWarn(ctx, "sql exec detail", nil, "gorm", gormUtils.FileWithLineNum(), "slow sql", slowLog, "elapsed time", fmt.Sprintf("%f(ms)", float64(elapsed.Nanoseconds())/1e6), "rows", rows, "sql", sql)
}
case l.LogLevel == gormLogger.Info:
sql, rows := fc()
if rows == -1 {
ZDebug(ctx, "sql exec detail", "gorm", gormUtils.FileWithLineNum(), "elapsed time", fmt.Sprintf("%f(ms)", float64(elapsed.Nanoseconds())/1e6), "sql", sql)
} else {
ZDebug(ctx, "sql exec detail", "gorm", gormUtils.FileWithLineNum(), "elapsed time", fmt.Sprintf("%f(ms)", float64(elapsed.Nanoseconds())/1e6), "rows", rows, "sql", sql)
}
}
}
30 changes: 30 additions & 0 deletions log/zk_logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package log

import (
"context"
"fmt"
)

type ZkLogger struct{}

func NewZkLogger() *ZkLogger {
return &ZkLogger{}
}

func (l *ZkLogger) Printf(format string, a ...interface{}) {
ZInfo(context.Background(), "zookeeper output", "msg", fmt.Sprintf(format, a...))
}
127 changes: 127 additions & 0 deletions utils/strings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package utils

import (
"encoding/json"
"strconv"
)

func IntToString(i int) string {
return strconv.FormatInt(int64(i), 10)
}

func StringToInt(i string) int {
j, _ := strconv.Atoi(i)
return j
}
func StringToInt64(i string) int64 {
j, _ := strconv.ParseInt(i, 10, 64)
return j
}
func StringToInt32(i string) int32 {
j, _ := strconv.ParseInt(i, 10, 64)
return int32(j)
}
func Int32ToString(i int32) string {
return strconv.FormatInt(int64(i), 10)
}

func Uint32ToString(i uint32) string {
return strconv.FormatInt(int64(i), 10)
}

// judge a string whether in the string list
func IsContain(target string, List []string) bool {
for _, element := range List {

if target == element {
return true
}
}
return false
}
func IsContainInt32(target int32, List []int32) bool {
for _, element := range List {
if target == element {
return true
}
}
return false
}
func IsContainInt(target int, List []int) bool {
for _, element := range List {
if target == element {
return true
}
}
return false
}
func InterfaceArrayToStringArray(data []interface{}) (i []string) {
for _, param := range data {
i = append(i, param.(string))
}
return i
}

func StructToJsonBytes(param interface{}) []byte {
dataType, _ := json.Marshal(param)
return dataType
}

// The incoming parameter must be a pointer
func JsonStringToStruct(s string, args interface{}) error {
err := json.Unmarshal([]byte(s), args)
return err
}

func Int64ToString(i int64) string {
return strconv.FormatInt(i, 10)
}

func RemoveDuplicateElement(idList []string) []string {
result := make([]string, 0, len(idList))
temp := map[string]struct{}{}
for _, item := range idList {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
result = append(result, item)
}
}
return result
}

func RemoveDuplicate[T comparable](arr []T) []T {
result := make([]T, 0, len(arr))
temp := map[T]struct{}{}
for _, item := range arr {
if _, ok := temp[item]; !ok {
temp[item] = struct{}{}
result = append(result, item)
}
}
return result
}

func IsDuplicateStringSlice(arr []string) bool {
t := make(map[string]struct{})
for _, s := range arr {
if _, ok := t[s]; ok {
return true
}
t[s] = struct{}{}
}
return false
}

0 comments on commit 0edcd3c

Please sign in to comment.