登录相关处理
This commit is contained in:
21
utils/auth/valid_code.go
Normal file
21
utils/auth/valid_code.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func GenerateVerificationCode() string {
|
||||
var code string
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
// 生成两个 10-99 之间的随机数
|
||||
a := rand.Intn(90-10+1) + 10
|
||||
b := rand.Intn(90-10+1) + 10
|
||||
c := rand.Intn(90-10+1) + 10
|
||||
// 将随机数拼接到验证码字符串
|
||||
code += fmt.Sprintf("%d%d%d", a, b, c)
|
||||
}
|
||||
|
||||
return code
|
||||
}
|
||||
@@ -6,5 +6,9 @@ type ErrorCode struct {
|
||||
}
|
||||
|
||||
var (
|
||||
ErrEncGcm = &ErrorCode{Code: 10001, Message: "gmc加密错误"}
|
||||
|
||||
ErrParamParse = &ErrorCode{Code: 10100, Message: "参数解析错误"}
|
||||
|
||||
ErrEmailFormat = &ErrorCode{Code: 10101, Message: "email 格式错误"}
|
||||
)
|
||||
|
||||
@@ -34,7 +34,7 @@ func (resp *Response) setData(Data []interface{}) {
|
||||
}
|
||||
|
||||
if len(Data) == 1 {
|
||||
resp.Data = Data
|
||||
resp.Data = Data[0]
|
||||
} else {
|
||||
resp.Data = Data
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ func SetCors(router *gin.Engine) {
|
||||
router.OPTIONS("/*path", func(c *gin.Context) {
|
||||
c.Header("Access-Control-Allow-Origin", "*") // 可以根据实际情况改为特定域名
|
||||
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization")
|
||||
c.Header("Access-Control-Allow-Headers", "*")
|
||||
c.Header("Access-Control-Allow-Credentials", "true")
|
||||
c.Status(http.StatusOK)
|
||||
})
|
||||
@@ -20,7 +20,7 @@ func SetCors(router *gin.Engine) {
|
||||
router.Use(func(c *gin.Context) {
|
||||
c.Header("Access-Control-Allow-Origin", "*") // 允许所有域名跨域访问,也可以指定特定的域名
|
||||
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization")
|
||||
c.Header("Access-Control-Allow-Headers", "*")
|
||||
c.Header("Access-Control-Allow-Credentials", "true")
|
||||
c.Next()
|
||||
})
|
||||
|
||||
15
utils/email/verify.go
Normal file
15
utils/email/verify.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package email
|
||||
|
||||
import "regexp"
|
||||
|
||||
// 验证是否邮箱
|
||||
func IsEmailValid(email string) bool {
|
||||
// 邮箱正则表达式
|
||||
regex := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
|
||||
|
||||
// 编译正则表达式
|
||||
regexPattern := regexp.MustCompile(regex)
|
||||
|
||||
// 根据正则表达式验证邮箱
|
||||
return regexPattern.MatchString(email)
|
||||
}
|
||||
85
utils/log/json_format.go
Normal file
85
utils/log/json_format.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type levelSkip struct {
|
||||
Skip int
|
||||
Once sync.Once
|
||||
}
|
||||
|
||||
// JSONFormatter formats logs into parsable json
|
||||
type JSONFormatter struct {
|
||||
skip []*levelSkip
|
||||
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
// Format renders a single log entry
|
||||
func (h *JSONFormatter) Format(e *logrus.Entry) ([]byte, error) {
|
||||
|
||||
skipOnce := h.skip[int(e.Level)]
|
||||
skipOnce.Once.Do(func() {
|
||||
for i := 4; i < 100; i++ {
|
||||
// log.Println(i)
|
||||
if pc, _, _, ok := runtime.Caller(i); ok {
|
||||
funcStruct := runtime.FuncForPC(pc)
|
||||
// log.Println(funcStruct.Name(), file, line)
|
||||
if !strings.Contains(funcStruct.Name(), "github.com/sirupsen/logrus.") {
|
||||
skipOnce.Skip++
|
||||
if skipOnce.Skip >= 2 {
|
||||
skipOnce.Skip = i - 3
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
var fileinfo string
|
||||
if _, file, line, ok := runtime.Caller(skipOnce.Skip); ok {
|
||||
if e.Level == logrus.InfoLevel {
|
||||
fileinfo = fmt.Sprintf("%s:%d", file, line)
|
||||
} else {
|
||||
ps := strings.Split(file, "/")
|
||||
ps = ps[len(ps)-4:]
|
||||
fileinfo = fmt.Sprintf("%s:%d", strings.Join(ps, "/"), line)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var Data map[string]any = make(map[string]any, 4)
|
||||
|
||||
Data[logrus.FieldKeyTime] = e.Time.Format(time.RFC3339)
|
||||
Data[logrus.FieldKeyMsg] = e.Message
|
||||
Data[logrus.FieldKeyLevel] = e.Level
|
||||
Data[logrus.FieldKeyFile] = fileinfo
|
||||
|
||||
var b *bytes.Buffer
|
||||
if e.Buffer != nil {
|
||||
b = e.Buffer
|
||||
} else {
|
||||
b = &bytes.Buffer{}
|
||||
}
|
||||
|
||||
encoder := json.NewEncoder(b)
|
||||
encoder.SetEscapeHTML(false)
|
||||
|
||||
if err := encoder.Encode(Data); err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal fields to JSON, %w", err)
|
||||
}
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
252
utils/log/log.go
Normal file
252
utils/log/log.go
Normal file
@@ -0,0 +1,252 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var l *logrus.Logger
|
||||
|
||||
func init() {
|
||||
l = logrus.New()
|
||||
|
||||
// 配置 Logstash 作为输出
|
||||
|
||||
l.AddHook(NewUTCTimeHook())
|
||||
jf := &JSONFormatter{
|
||||
skip: make([]*levelSkip, len(logrus.AllLevels)),
|
||||
}
|
||||
|
||||
for i := range jf.skip {
|
||||
jf.skip[i] = &levelSkip{}
|
||||
}
|
||||
|
||||
l.Formatter = jf
|
||||
|
||||
// l.AddHook(&SkipHook{})
|
||||
|
||||
l.SetReportCaller(true)
|
||||
|
||||
}
|
||||
|
||||
type SkipHook struct {
|
||||
autoSkip int
|
||||
Formatter func(*logrus.Hook, *logrus.Entry) error
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (h *SkipHook) Levels() []logrus.Level {
|
||||
return logrus.AllLevels
|
||||
}
|
||||
|
||||
func (h *SkipHook) Fire(e *logrus.Entry) error {
|
||||
h.once.Do(func() {
|
||||
for i := 4; i < 100; i++ {
|
||||
log.Println(i)
|
||||
if pc, file, line, ok := runtime.Caller(i); ok {
|
||||
funcStruct := runtime.FuncForPC(pc)
|
||||
log.Println(funcStruct.Name(), file, line)
|
||||
if !strings.Contains(funcStruct.Name(), "github.com/sirupsen/logrus.") {
|
||||
h.autoSkip++
|
||||
if h.autoSkip >= 2 {
|
||||
h.autoSkip = i - 3
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
if _, file, line, ok := runtime.Caller(h.autoSkip); ok {
|
||||
// funcStruct := runtime.FuncForPC(pc)
|
||||
// log.Println(file, line, funcStruct.Name())
|
||||
// funcName := funcStruct.Name()
|
||||
file := fmt.Sprintf("%s:%d", file, line)
|
||||
e.Data["file"] = file
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 自定义钩子以设置时间为UTC
|
||||
type UTCTimeHook struct{}
|
||||
|
||||
func NewUTCTimeHook() *UTCTimeHook {
|
||||
return &UTCTimeHook{}
|
||||
}
|
||||
|
||||
func (hook *UTCTimeHook) Levels() []logrus.Level {
|
||||
return logrus.AllLevels
|
||||
}
|
||||
|
||||
func (hook *UTCTimeHook) Fire(entry *logrus.Entry) error {
|
||||
entry.Time = time.Now().UTC()
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithField allocates a new entry and adds a field to it.
|
||||
// Debug, Print, Info, Warn, Error, Fatal or Panic must be then applied to
|
||||
// this new returned entry.
|
||||
// If you want multiple fields, use `WithFields`.
|
||||
func WithField(key string, value interface{}) *logrus.Entry {
|
||||
return l.WithField(key, value)
|
||||
}
|
||||
|
||||
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
||||
// each `Field`.
|
||||
func WithFields(fields logrus.Fields) *logrus.Entry {
|
||||
return l.WithFields(fields)
|
||||
}
|
||||
|
||||
// Add an error as single field to the log entry. All it does is call
|
||||
// `WithError` for the given `error`.
|
||||
func WithError(err error) *logrus.Entry {
|
||||
|
||||
return l.WithError(err)
|
||||
}
|
||||
|
||||
// Add a context to the log entry.
|
||||
func WithContext(ctx context.Context) *logrus.Entry {
|
||||
|
||||
return l.WithContext(ctx)
|
||||
}
|
||||
|
||||
// Overrides the time of the log entry.
|
||||
func WithTime(t time.Time) *logrus.Entry {
|
||||
|
||||
return l.WithTime(t)
|
||||
}
|
||||
|
||||
func Logf(level logrus.Level, format string, args ...interface{}) {
|
||||
l.Logf(level, format, args...)
|
||||
}
|
||||
|
||||
func Tracef(format string, args ...interface{}) {
|
||||
l.Tracef(format, args...)
|
||||
}
|
||||
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
l.Debugf(format, args...)
|
||||
}
|
||||
|
||||
func Infof(format string, args ...interface{}) {
|
||||
l.Infof(format, args...)
|
||||
}
|
||||
|
||||
func Printf(format string, args ...interface{}) {
|
||||
l.Printf(format, args...)
|
||||
}
|
||||
|
||||
func Warnf(format string, args ...interface{}) {
|
||||
l.Warnf(format, args...)
|
||||
}
|
||||
|
||||
func Warningf(format string, args ...interface{}) {
|
||||
l.Warningf(format, args...)
|
||||
}
|
||||
|
||||
func Errorf(format string, args ...interface{}) {
|
||||
l.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
l.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
func Panicf(format string, args ...interface{}) {
|
||||
l.Panicf(format, args...)
|
||||
}
|
||||
|
||||
func Log(level logrus.Level, args ...interface{}) {
|
||||
l.Log(level, args...)
|
||||
}
|
||||
|
||||
func Trace(args ...interface{}) {
|
||||
l.Trace(args...)
|
||||
}
|
||||
|
||||
func Debug(args ...interface{}) {
|
||||
l.Debug(args...)
|
||||
}
|
||||
|
||||
func Info(args ...interface{}) {
|
||||
l.Info(args...)
|
||||
}
|
||||
|
||||
func Print(args ...interface{}) {
|
||||
l.Print(args...)
|
||||
}
|
||||
|
||||
func Warn(args ...interface{}) {
|
||||
l.Warn(args...)
|
||||
}
|
||||
|
||||
func Warning(args ...interface{}) {
|
||||
l.Warning(args...)
|
||||
}
|
||||
|
||||
func Error(args ...interface{}) {
|
||||
l.Error(args...)
|
||||
}
|
||||
|
||||
func Fatal(args ...interface{}) {
|
||||
l.Fatal(args...)
|
||||
}
|
||||
|
||||
func Panic(args ...interface{}) {
|
||||
l.Panic(args...)
|
||||
}
|
||||
|
||||
func Logln(level logrus.Level, args ...interface{}) {
|
||||
l.Logln(level, args...)
|
||||
}
|
||||
|
||||
func Traceln(args ...interface{}) {
|
||||
l.Traceln(args...)
|
||||
}
|
||||
|
||||
func Debugln(args ...interface{}) {
|
||||
l.Debugln(args...)
|
||||
}
|
||||
|
||||
func Infoln(args ...interface{}) {
|
||||
l.Infoln(args...)
|
||||
}
|
||||
|
||||
func Println(args ...interface{}) {
|
||||
l.Println(args...)
|
||||
}
|
||||
|
||||
func Warnln(args ...interface{}) {
|
||||
l.Warnln(args...)
|
||||
}
|
||||
|
||||
func Warningln(args ...interface{}) {
|
||||
l.Warningln(args...)
|
||||
}
|
||||
|
||||
func Errorln(args ...interface{}) {
|
||||
l.Errorln(args...)
|
||||
}
|
||||
|
||||
func Fatalln(args ...interface{}) {
|
||||
l.Fatalln(args...)
|
||||
}
|
||||
|
||||
func Panicln(args ...interface{}) {
|
||||
l.Panicln(args...)
|
||||
}
|
||||
|
||||
func Exit(code int) {
|
||||
l.Exit(code)
|
||||
}
|
||||
28
utils/log/log_time.go
Normal file
28
utils/log/log_time.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 跟踪时间
|
||||
|
||||
func DebuglnTrackTime(do func(), fargs ...interface{}) {
|
||||
now := time.Now()
|
||||
do()
|
||||
var t interface{} = fmt.Sprintf("[%dms]", time.Since(now).Milliseconds())
|
||||
var out []interface{}
|
||||
out = append(out, t)
|
||||
out = append(out, fargs...)
|
||||
l.Debugln(out...)
|
||||
}
|
||||
|
||||
func InfolnTrackTime(do func(), fargs ...interface{}) {
|
||||
now := time.Now()
|
||||
do()
|
||||
var t interface{} = fmt.Sprintf("[%dms]", time.Since(now).Milliseconds())
|
||||
var out []interface{}
|
||||
out = append(out, t)
|
||||
out = append(out, fargs...)
|
||||
l.Infoln(out...)
|
||||
}
|
||||
74
utils/log/readme.md
Normal file
74
utils/log/readme.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Log Package README
|
||||
|
||||
## 概述
|
||||
此`log`包提供了一套全面的日志记录功能,基于`github.com/sirupsen/logrus`库进行了深度定制和扩展。通过本包,您可以实现多级别的日志输出,并能灵活控制日志格式、时间戳显示以及调用栈信息等。
|
||||
用于fusen的全部服务的统一格式化, 便于运维统一处理。
|
||||
|
||||
### 功能特性
|
||||
1. **多级别日志**:支持`Trace`、`Debug`、`Info`、`Warn`、`Error`、`Fatal`和`Panic`等多种日志级别。
|
||||
|
||||
2. **追踪时间**:包含`DebuglnTrackTime`与`InfolnTrackTime`函数,用于执行指定函数并在输出时附加执行耗时(毫秒)。
|
||||
|
||||
3. **UTC时间**:使用了自定义的`UTCTimeHook`钩子,确保所有日志的时间戳采用协调世界时(UTC)格式。
|
||||
|
||||
4. **JSON格式化**:实现了`JSONFormatter`结构体,将日志条目格式化为可解析的JSON字符串。它自动跳过与logrus库自身相关的调用层级,以便更准确地显示应用代码中的文件和行号信息。
|
||||
|
||||
5. **上下文关联**:提供了`WithContext`方法,允许在日志条目中携带Go context.Context,便于进行请求级或事务级的跟踪。
|
||||
|
||||
6. **错误处理**:通过`WithError`方法可以在日志条目中便捷地添加错误对象。
|
||||
|
||||
7. **时间戳覆盖**:`WithTime`方法允许开发者为日志条目设置特定的时间戳。
|
||||
|
||||
8. **灵活格式化**:除了基本的日志输出外,还支持带有格式字符串的函数如`Printf`、`Debugf`等,以适应不同的消息格式需求。
|
||||
|
||||
9. **源码定位**:已启用报告调用者位置的功能,每条日志都会附带其产生的源代码文件名及行号。
|
||||
|
||||
### 使用示例
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/yourorg/log" // 替换为实际导入路径
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Debugln("This is a debug message.")
|
||||
log.Infoln("Normal info message.")
|
||||
|
||||
// 添加自定义字段并格式化输出
|
||||
entry := log.WithField("user_id", "123")
|
||||
entry.Info("User logged in.")
|
||||
|
||||
// 记录并追踪函数执行时间
|
||||
log.DebuglnTrackTime(func() {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}, "Function execution")
|
||||
|
||||
// 设置日志上下文
|
||||
ctx := context.Background()
|
||||
ctx = log.WithContext(ctx, "request_id", "abc123")
|
||||
log.Infof(ctx, "Received request with ID: %s", "abc123")
|
||||
|
||||
// 输出JSON格式化的日志
|
||||
log.SetFormatter(&log.JSONFormatter{})
|
||||
log.Warn("JSON-formatted warning.")
|
||||
}
|
||||
```
|
||||
|
||||
### 配置选项
|
||||
- 在初始化阶段,已经配置了Logstash作为日志输出的目标。
|
||||
- 可通过修改`l.Formatter`属性来更换或自定义日志格式器。
|
||||
- 通过`AddHook`方法可以添加自定义的钩子,比如这里有一个未使用的`SkipHook`,它可以用来过滤调用栈。
|
||||
|
||||
### 注意事项
|
||||
- 当需要同时记录多个字段时,请使用`WithFields`方法而不是多次调用`WithField`。
|
||||
- 若要调整日志输出级别,请直接操作全局logger实例的level设置。
|
||||
|
||||
### 结构体与方法详解
|
||||
- `levelSkip` 结构体用于在堆栈跟踪过程中计算需要跳过的层级数。
|
||||
- `UTCTimeHook` 是一个自定义钩子,当触发时会将日志条目的时间戳设置为当前UTC时间。
|
||||
- `JSONFormatter` 实现了`Format`方法,将日志条目转化为JSON格式。
|
||||
|
||||
|
||||
1
utils/log/tx/log_test.go
Normal file
1
utils/log/tx/log_test.go
Normal file
@@ -0,0 +1 @@
|
||||
package log_test
|
||||
Reference in New Issue
Block a user