首页 文章 精选 留言 我的

精选列表

搜索[goframe],共213篇文章
优秀的个人博客,低调大师

GoFrame 框架:日志配置管理

介绍 通过一个完整例子,在 gogf/gf 框架中合理管理日志。 有什么使用场景? 日志自动滚动 分成多个日志文件 日志格式修改 等等 我们将会使用 rk-boot 来启动 gogf/gf 框架的微服务。 请访问如下地址获取完整教程: https://rkdocs.netlify.app/cn 安装 go get github.com/rookie-ninja/rk-boot/gf 简述概念 rk-boot 使用如下两个库管理日志。 zap 管理日志实例 lumberjack 管理日志滚动 rk-boot 定义了两种日志类型,会在后面详细介绍,这里先做个简短介绍。 ZapLogger: 标准日志,用于记录 Error, Info 等。 EventLogger: JSON 或者 Console 格式,用于记录 Event,例如 RPC 请求。 快速开始 在这个例子中,我们会试着改变 zap 日志的路径和格式。 1.创建 boot.yaml --- zapLogger: - name: zap-log # Required zap: encoding: json # Optional, options: console, json outputPaths: ["logs/zap.log"] # Optional gf: - name: greeter port: 8080 enabled: true 2.创建 main.go 往 zap-log 日志实例中写个日志。 // Copyright (c) 2021 rookie-ninja // // Use of this source code is governed by an Apache-style // license that can be found in the LICENSE file. package main import ( "context" "github.com/rookie-ninja/rk-boot" _ "github.com/rookie-ninja/rk-boot/gf" ) func main() { // Create a new boot instance. boot := rkboot.NewBoot() // Bootstrap boot.Bootstrap(context.Background()) // Write zap log boot.GetZapLoggerEntry("zap-log").GetLogger().Info("This is zap-log") // Wait for shutdown sig boot.WaitForShutdownSig(context.Background()) } 3.验证 文件夹结构 ├── boot.yaml ├── go.mod ├── go.sum ├── logs │ └── zap.log └── main.go 日志输出 {"level":"INFO","ts":"2021-10-21T02:10:09.279+0800","msg":"This is zap-log"} 配置 EventLogger 上面的例子中,我们配置了 zap 日志,这回我们修改一下 EventLogger。 1.创建 boot.yaml --- eventLogger: - name: event-log # Required encoding: json # Optional, options: console, json outputPaths: ["logs/event.log"] # Optional gf: - name: greeter port: 8080 enabled: true 2.创建 main.go 往 event-log 实例中写入日志。 package main import ( "context" "github.com/rookie-ninja/rk-boot" "github.com/rookie-ninja/rk-entry/entry" ) func main() { // Create a new boot instance. boot := rkboot.NewBoot() // Bootstrap boot.Bootstrap(context.Background()) // Write event log helper := boot.GetEventLoggerEntry("event-log").GetEventHelper() event := helper.Start("demo-event") event.AddPair("key", "value") helper.Finish(event) // Wait for shutdown sig boot.WaitForShutdownSig(context.Background()) } 3.启动 main.go $ go run main.go 4.验证 文件夹结构 ├── boot.yaml ├── go.mod ├── go.sum ├── logs │ └── event.log └── main.go 日志内容 {"endTime": "2022-01-18T22:18:44.926+0800", "startTime": "2022-01-18T22:18:44.926+0800", "elapsedNano": 746, "timezone": "CST", "ids": {"eventId":"2aaea6f5-c7ac-4245-ac50-857726f3ede4"}, "app": {"appName":"rk","appVersion":"","entryName":"","entryType":""}, "env": {"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin","realm":"*","region":"*"}, "payloads": {}, "error": {}, "counters": {}, "pairs": {"key":"value"}, "timing": {}, "remoteAddr": "localhost", "operation": "demo-event", "eventStatus": "Ended", "resCode": "OK"} 概念 上面的例子中,我们尝试了 ZapLogger 和 EventLogger。接下来我们看看 rk-boot 是如何实现的,并且怎么使用。 架构 ZapLoggerEntry ZapLoggerEntry 是 zap 实例的一个封装。 // ZapLoggerEntry contains bellow fields. // 1: EntryName: Name of entry. // 2: EntryType: Type of entry which is ZapLoggerEntryType. // 3: EntryDescription: Description of ZapLoggerEntry. // 4: Logger: zap.Logger which was initialized at the beginning. // 5: LoggerConfig: zap.Logger config which was initialized at the beginning which is not accessible after initialization.. // 6: LumberjackConfig: lumberjack.Logger which was initialized at the beginning. type ZapLoggerEntry struct { EntryName string `yaml:"entryName" json:"entryName"` EntryType string `yaml:"entryType" json:"entryType"` EntryDescription string `yaml:"entryDescription" json:"entryDescription"` Logger *zap.Logger `yaml:"-" json:"-"` LoggerConfig *zap.Config `yaml:"zapConfig" json:"zapConfig"` LumberjackConfig *lumberjack.Logger `yaml:"lumberjackConfig" json:"lumberjackConfig"` } 如何在 boot.yaml 里配置 ZapLoggerEntry? ZapLoggerEntry 完全兼容 zap 和 lumberjack 的 YAML 结构。 用户可以根据需求,配置多个 ZapLogger 实例,并且通过 name 来访问。 完整配置: --- zapLogger: - name: zap-logger # Required description: "Description of entry" # Optional zap: level: info # Optional, default: info, options: [debug, DEBUG, info, INFO, warn, WARN, dpanic, DPANIC, panic, PANIC, fatal, FATAL] development: true # Optional, default: true disableCaller: false # Optional, default: false disableStacktrace: true # Optional, default: true sampling: # Optional, default: empty map initial: 0 thereafter: 0 encoding: console # Optional, default: "console", options: [console, json] encoderConfig: messageKey: "msg" # Optional, default: "msg" levelKey: "level" # Optional, default: "level" timeKey: "ts" # Optional, default: "ts" nameKey: "logger" # Optional, default: "logger" callerKey: "caller" # Optional, default: "caller" functionKey: "" # Optional, default: "" stacktraceKey: "stacktrace" # Optional, default: "stacktrace" lineEnding: "\n" # Optional, default: "\n" levelEncoder: "capitalColor" # Optional, default: "capitalColor", options: [capital, capitalColor, color, lowercase] timeEncoder: "iso8601" # Optional, default: "iso8601", options: [rfc3339nano, RFC3339Nano, rfc3339, RFC3339, iso8601, ISO8601, millis, nanos] durationEncoder: "string" # Optional, default: "string", options: [string, nanos, ms] callerEncoder: "" # Optional, default: "" nameEncoder: "" # Optional, default: "" consoleSeparator: "" # Optional, default: "" outputPaths: [ "stdout" ] # Optional, default: ["stdout"], stdout would be replaced if specified errorOutputPaths: [ "stderr" ] # Optional, default: ["stderr"], stderr would be replaced if specified initialFields: # Optional, default: empty map key: "value" lumberjack: # Optional filename: "rkapp-event.log" # Optional, default: It uses <processname>-lumberjack.log in os.TempDir() if empty. maxsize: 1024 # Optional, default: 1024 (MB) maxage: 7 # Optional, default: 7 (days) maxbackups: 3 # Optional, default: 3 (days) localtime: true # Optional, default: true compress: true # Optional, default: true 如何在代码里获取 ZapLogger? 通过 name 来访问。 boot := rkboot.NewBoot() // Access entry boot.GetZapLoggerEntry("zap-logger") // Access zap logger boot.GetZapLoggerEntry("zap-logger").GetLogger() // Access zap logger config boot.GetZapLoggerEntry("zap-logger").GetLoggerConfig() // Access lumberjack config boot.GetZapLoggerEntry("zap-logger").GetLumberjackConfig() EventLoggerEntry rk-boot 把每一个 RPC 请求看作一个 Event,并且使用 rk-query 中的 Event 类型来记录日志。 // EventLoggerEntry contains bellow fields. // 1: EntryName: Name of entry. // 2: EntryType: Type of entry which is EventLoggerEntryType. // 3: EntryDescription: Description of EventLoggerEntry. // 4: EventFactory: rkquery.EventFactory was initialized at the beginning. // 5: EventHelper: rkquery.EventHelper was initialized at the beginning. // 6: LoggerConfig: zap.Config which was initialized at the beginning which is not accessible after initialization. // 7: LumberjackConfig: lumberjack.Logger which was initialized at the beginning. type EventLoggerEntry struct { EntryName string `yaml:"entryName" json:"entryName"` EntryType string `yaml:"entryType" json:"entryType"` EntryDescription string `yaml:"entryDescription" json:"entryDescription"` EventFactory *rkquery.EventFactory `yaml:"-" json:"-"` EventHelper *rkquery.EventHelper `yaml:"-" json:"-"` LoggerConfig *zap.Config `yaml:"zapConfig" json:"zapConfig"` LumberjackConfig *lumberjack.Logger `yaml:"lumberjackConfig" json:"lumberjackConfig"` } EventLogger 字段 我们可以看到 EventLogger 打印出来的日志里,包含字段,介绍一下这些字段。 字段 详情 endTime 结束时间 startTime 开始时间 elapsedNano Event 时间开销(Nanoseconds) timezone 时区 ids 包含 eventId, requestId 和 traceId。如果原数据拦截器被启动,或者 event.SetRequest() 被用户调用,新的 RequestId 将会被使用,同时 eventId 与 requestId 会一模一样。 如果调用链拦截器被启动,traceId 将会被记录。 app 包含 appName, appVersion, entryName, entryType。 env 包含 arch, az, domain, hostname, localIP, os, realm, region. realm, region, az, domain 字段。这些字段来自系统环境变量(REALM,REGION,AZ,DOMAIN)。 "*" 代表环境变量为空。 payloads 包含 RPC 相关信息。 error 包含错误。 counters 通过 event.SetCounter() 来操作。 pairs 通过 event.AddPair() 来操作。 timing 通过 event.StartTimer() 和 event.EndTimer() 来操作。 remoteAddr RPC 远程地址。 operation RPC 名字。 resCode RPC 返回码。 eventStatus Ended 或者 InProgress 例子 ------------------------------------------------------------------------ endTime=2021-11-27T02:30:27.670807+08:00 startTime=2021-11-27T02:30:27.670745+08:00 elapsedNano=62536 timezone=CST ids={"eventId":"4bd9e16b-2b29-4773-8908-66c860bf6754"} app={"appName":"gf-demo","appVersion":"master-f948c90","entryName":"greeter","entryType":"GfEntry"} env={"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.6","os":"darwin","realm":"*","region":"*"} payloads={"apiMethod":"GET","apiPath":"/rk/v1/healthy","apiProtocol":"HTTP/1.1","apiQuery":"","userAgent":"curl/7.64.1"} error={} counters={} pairs={} timing={} remoteAddr=localhost:61726 operation=/rk/v1/healthy resCode=200 eventStatus=Ended EOE 如何在 boot.yaml 里配置 EventLoggerEntry? EventLoggerEntry 将会把 Application 名字注入到 Event 中。启动器会从 go.mod 文件中提取 Application 名字。 如果没有 go.mod 文件,启动器会使用默认的名字。 用户可以根据需求,配置多个 EventLogger 实例,并且通过 name 来访问。 完整配置: --- eventLogger: - name: event-logger # Required description: "This is description" # Optional encoding: console # Optional, default: console, options: console and json outputPaths: ["stdout"] # Optional lumberjack: # Optional filename: "rkapp-event.log" # Optional, default: It uses <processname>-lumberjack.log in os.TempDir() if empty. maxsize: 1024 # Optional, default: 1024 (MB) maxage: 7 # Optional, default: 7 (days) maxbackups: 3 # Optional, default: 3 (days) localtime: true # Optional, default: true compress: true # Optional, default: true 如何在代码里获取 EventLogger? 通过 name 来访问。 boot := rkboot.NewBoot() // Access entry boot.GetEventLoggerEntry("event-logger") // Access event factory boot.GetEventLoggerEntry("event-logger").GetEventFactory() // Access event helper boot.GetEventLoggerEntry("event-logger").GetEventHelper() // Access lumberjack config boot.GetEventLoggerEntry("event-logger").GetLumberjackConfig() 如何使用 Event? Event 是一个 interface,包含了若干方法,请参考:Event 常用方法: boot := rkboot.NewBoot() // Get EventHelper to create Event instance helper := boot.GetEventLoggerEntry("event-log").GetEventHelper() // Start and finish event event := helper.Start("demo-event") helper.Finish(event) // Add K/V event.AddPair("key", "value") // Start and end timer event.StartTimer("my-timer") event.EndTimer("my-timer") // Set counter event.SetCounter("my-counter", 1)

优秀的个人博客,低调大师

GoFrame 框架: 快速创建静态文件下载 Web 服务

介绍 本文介绍如何通过 rk-boot 快速搭建静态文件下载 Web 服务。 什么是 静态文件下载 Web UI? 通过配置文件,快速搭建可下载文件的 Web 服务。 请访问如下地址获取完整教程: https://rkdocs.netlify.app/cn 安装 go get github.com/rookie-ninja/rk-boot/gf 快速开始 rk-boot 提供了一个方便的方法,让用户快速实现网页【浏览和下载】静态文件的功能。 目前,rk-boot 支持如下文件源。如果用户希望支持更多的文件源,可以通过实现 http.FileSystem 接口来实现。 本地文件系统 pkger 1.创建 boot.yaml --- gf: - name: greeter # Required port: 8080 # Required enabled: true # Required static: enabled: true # Optional, default: false path: "/rk/v1/static" # Optional, default: /rk/v1/static sourceType: local # Required, options: pkger, local sourcePath: "." # Required, full path of source directory 2.创建 main.go // Copyright (c) 2021 rookie-ninja // // Use of this source code is governed by an Apache-style // license that can be found in the LICENSE file. package main import ( "context" "github.com/rookie-ninja/rk-boot" _ "github.com/rookie-ninja/rk-boot/gf" ) // Application entrance. func main() { // Create a new boot instance. boot := rkboot.NewBoot() // Bootstrap boot.Bootstrap(context.Background()) // Wait for shutdown sig boot.WaitForShutdownSig(context.Background()) } 3.文件夹结构 . ├── boot.yaml ├── go.mod ├── go.sum └── main.go 0 directories, 4 files 4.验证 访问 http://localhost:8080/rk/v1/static 从 pkger 读取文件 (嵌入式静态文件) pkger 是一个可以把静态文件,嵌入到 .go 文件的工具。 这个例子中,我们把当前文件夹下的所有文件,都嵌入到 pkger.go 文件中。 这样做的好处就是,在部署的时候,可以不用考虑复制一堆文件夹结构。 1.下载 pkger 命令行 go get github.com/markbates/pkger/cmd/pkger 2.创建 boot.yaml pkger 会使用 module 来区分不同的 package,所以,sourcePath 里,我们添加了相应 module 的前缀。 --- gf: - name: greeter # Required port: 8080 # Required enabled: true # Required static: enabled: true # Optional, default: false path: "/rk/v1/static" # Optional, default: /rk/v1/static sourceType: pkger # Required, options: pkger, local sourcePath: "github.com/rookie-ninja/rk-demo:/" # Required, full path of source directory 3.创建 main.go 代码中,有两个地方需要注意。 pkger.Include("./") 这段代码不做任何事情,是告诉 pkger 命令行打包哪些文件。 _ “github.com/rookie-ninja/rk-demo/internal” 一定要这么引入,因为我们会把 pkger.go 文件放到 internal/pkger.go 中,pkger.go 文件里定一个一个 variable,只有这么引入,才可以在编译 main.go 的时候,顺利引入 variable。 // Copyright (c) 2021 rookie-ninja // // Use of this source code is governed by an Apache-style // license that can be found in the LICENSE file. package main import ( "context" "github.com/markbates/pkger" "github.com/rookie-ninja/rk-boot" _ "github.com/rookie-ninja/rk-boot/gf" // Must be present in order to make pkger load embedded files into memory. _ "github.com/rookie-ninja/rk-demo/internal" ) func init() { // This is used while running pkger CLI pkger.Include("./") } // Application entrance. func main() { // Create a new boot instance. boot := rkboot.NewBoot() // Bootstrap boot.Bootstrap(context.Background()) // Wait for shutdown sig boot.WaitForShutdownSig(context.Background()) } 4.生成 pkger.go pkger -o internal 5.文件夹结构 . ├── boot.yaml ├── go.mod ├── go.sum ├── internal │ └── pkged.go └── main.go 1 directory, 5 files 6.验证 访问 http://localhost:8080/rk/v1/static 自定义文件源 我们将使用 afero package 里面的 memFs 作为例子。 如果想要从类似 AWS S3 中读取,用户可以实现一个属于自己的 http.FileSystem。 rk-boot 会在后续的更新中,逐渐实现这些功能。 1.创建 boot.yaml --- gf: - name: greeter # Required port: 8080 # Required enabled: true # Required 2.创建 main.go 我们在 memFs 中创建了一个 /folder 文件夹和 一个 /file.txt 文件。 // Copyright (c) 2021 rookie-ninja // // Use of this source code is governed by an Apache-style // license that can be found in the LICENSE file. package main import ( "context" "github.com/rookie-ninja/rk-boot" "github.com/rookie-ninja/rk-boot/gf" "github.com/spf13/afero" "os" ) // Application entrance. func main() { // Create a new boot instance. boot := rkboot.NewBoot() // Create a memory fs fs := afero.NewHttpFs(afero.NewMemMapFs()) // Add folder and file.txt into memory fs fs.MkdirAll("/folder", os.ModePerm) f, _ := fs.Create("/file.txt") f.Write([]byte("this is my content!")) f.Close() // Set StaticFileEntry gfEntry := rkbootgf.GetGfEntry("greeter") gfEntry.StaticFileEntry = rkentry.RegisterStaticFileHandlerEntry( rkentry.WithPathStatic("/rk/v1/static"), rkentry.WithFileSystemStatic(fs)) // Bootstrap boot.Bootstrap(context.Background()) // Wait for shutdown sig boot.WaitForShutdownSig(context.Background()) } 3.验证 访问 http://localhost:8080/rk/v1/static

优秀的个人博客,低调大师

gtoken v1.3.15 发布,基于 GoFrame 的 token 插件

本次更新: 1. gf升级为V1.12.1 2. 加入全局拦截支持,方便调整认证和其他中间件执行顺序 // 启动gtoken gtoken := &gtoken.GfToken{ LoginPath: "/login", LoginBeforeFunc: loginFunc, LogoutPath: "/user/logout", AuthPaths: g.SliceStr{"/user", "/system"}, // 这里是按照前缀拦截,拦截/user /user/list /user/add ... GlobalMiddleware: true, // 开启全局拦截,默认关闭 } gtoken.Start() gtoken介绍 基于gf框架的token插件,通过服务端验证方式实现token认证;已完全可以支撑线上token认证,并支持集群模式;使用简单,大家可以放心使用; 支持单机gcache和集群gredis模式; # 配置文件 # 缓存模式 1 gcache 2 gredis cache-mode = 2 支持简单token认证 加入缓存自动续期功能 // 注:通过MaxRefresh,默认当用户第五天访问时,自动再进行五天续期 // 超时时间 默认10天 Timeout int // 缓存刷新时间 默认为超时时间的一半 MaxRefresh int 支持全局拦截或者深度路径拦截,便于根据个人需求定制拦截器 // 是否是全局认证 GlobalMiddleware bool 框架使用简单,只需要设置登录验证方法以及登录、登出、拦截路径即可; github地址:https://github.com/goflyfox/gtoken gitee地址:https://gitee.com/goflyfox/gtoken gtoken优势 有效的避免了jwt服务端无法退出问题; 可以解决jwt无法作废已颁布的令牌; 用户扩展信息仍存储在服务端,可有效的减少传输空间; gtoken支撑单点应用使用内存存储,也支持集群使用redis存储; 支持缓存自动续期,并且不需要客户端进行实现; 安装教程 gopath模式:go get github.com/goflyfox/gtoken 或者 使用go.mod添加 :require github.com/goflyfox/gtoken latest 使用说明 只需要配置登录路径、登出路径、拦截路径以及登录校验实现即可 // 启动gtoken gtoken := &gtoken.GfToken{ LoginPath: "/login", LoginBeforeFunc: loginFunc, LogoutPath: "/user/logout", AuthPaths: g.SliceStr{"/user", "/system"}, // 这里是按照前缀拦截,拦截/user /user/list /user/add ... GlobalMiddleware: true, // 开启全局拦截,默认关闭 } gtoken.Start() 登录方法实现 func Login(r *ghttp.Request) (string, interface{}) { username := r.GetPostString("username") passwd := r.GetPostString("passwd") // TODO 进行登录校验 return username, "" } 逻辑测试 可运行api_test.go进行测试并查看结果;验证逻辑说明: 访问用户信息,提示未携带token 登录后,携带token访问正常 登出成功 携带之前token访问,提示未登录 --- PASS: TestSystemUser (0.00s) api_test.go:43: 1. not login and visit user api_test.go:50: {"code":-1,"data":"","msg":"query token fail"} api_test.go:63: 2. execute login and visit user api_test.go:66: {"code":0,"msg":"success","data":"system user"} api_test.go:72: 3. execute logout api_test.go:75: {"code":0,"msg":"success","data":"logout success"} api_test.go:81: 4. visit user api_test.go:86: {"code":-1,"msg":"login timeout or not login","data":""} 感谢 gf框架https://github.com/gogf/gf

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册