Skip to content

Commit 684d80b

Browse files
root小源
andcommitted
feat: add go.mod, GitHub Actions CI, and YAML config support
- Add go.mod for Go modules dependency management - Add GitHub Actions workflow (test + lint) - Add YAML configuration parser with full test coverage - Add config.yaml example file Co-authored-by: 小源 <ai@devfeel.com>
1 parent d2d1158 commit 684d80b

6 files changed

Lines changed: 501 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [master, develop, aicode]
6+
pull_request:
7+
branches: [aicode]
8+
9+
jobs:
10+
test:
11+
name: Test
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Set up Go
19+
uses: actions/setup-go@v5
20+
with:
21+
go-version: '1.18'
22+
cache: true
23+
24+
- name: Download dependencies
25+
run: go mod download
26+
27+
- name: Build
28+
run: go build -v ./...
29+
30+
- name: Run tests
31+
run: go test -v -race -coverprofile=coverage.out ./...
32+
33+
- name: Upload coverage
34+
uses: actions/upload-artifact@v4
35+
with:
36+
name: coverage
37+
path: coverage.out
38+
39+
lint:
40+
name: Lint
41+
runs-on: ubuntu-latest
42+
43+
steps:
44+
- name: Checkout code
45+
uses: actions/checkout@v4
46+
47+
- name: Set up Go
48+
uses: actions/setup-go@v5
49+
with:
50+
go-version: '1.18'
51+
cache: true
52+
53+
- name: Run golangci-lint
54+
uses: golangci/golangci-lint-action@v6
55+
with:
56+
version: latest

config/config.yaml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# dotlog YAML 配置文件示例
2+
# 使用说明: 将文件名传递给 StartLogService("config.yaml") 即可
3+
4+
global:
5+
isLog: true
6+
chanSize: 1000
7+
innerLogPath: "./"
8+
innerLogEncode: "utf-8"
9+
10+
# 自定义变量
11+
variables:
12+
- name: LogDir
13+
value: "./logs/"
14+
- name: LogDateDir
15+
value: "./logs/{year}/{month}/{day}/"
16+
17+
# 日志输出目标
18+
targets:
19+
# 文件输出
20+
file:
21+
- name: FileLogger
22+
isLog: true
23+
layout: "{datetime} - {message}"
24+
encode: "utf-8"
25+
fileMaxSize: 10240 # KB
26+
fileName: "./logs/app.log"
27+
28+
# 标准输出
29+
fmt:
30+
- name: StdoutLogger
31+
isLog: true
32+
layout: "[{level}] {datetime} - {message}"
33+
encode: "utf-8"
34+
35+
# UDP 输出 (可选)
36+
# udp:
37+
# - name: UdpLogger
38+
# isLog: true
39+
# layout: "{message}"
40+
# encode: "utf-8"
41+
# remoteIP: "127.0.0.1:9000"
42+
43+
# HTTP 输出 (可选)
44+
# http:
45+
# - name: HttpLogger
46+
# isLog: true
47+
# layout: "{message}"
48+
# encode: "utf-8"
49+
# httpUrl: "http://localhost:8080/log"
50+
51+
# 日志记录器配置
52+
loggers:
53+
- name: FileLogger
54+
isLog: true
55+
layout: "{datetime} - {message}"
56+
configMode: "file"
57+
levels:
58+
- level: info
59+
targets: "FileLogger"
60+
isLog: true
61+
- level: error
62+
targets: "FileLogger"
63+
isLog: true
64+
65+
- name: StdoutLogger
66+
isLog: true
67+
layout: "[{level}] {datetime} - {message}"
68+
configMode: "fmt"
69+
levels:
70+
- level: debug
71+
targets: "StdoutLogger"
72+
isLog: true
73+
- level: info
74+
targets: "StdoutLogger"
75+
isLog: true

config/yaml.go

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"gopkg.in/yaml.v3"
8+
)
9+
10+
// yamlConfig YAML 配置结构
11+
type yamlConfig struct {
12+
Global globalConfig `yaml:"global"`
13+
Variables []variableConfig `yaml:"variables"`
14+
Targets targetList `yaml:"targets"`
15+
Loggers []loggerConfig `yaml:"loggers"`
16+
}
17+
18+
type globalConfig struct {
19+
IsLog bool `yaml:"isLog"`
20+
ChanSize int `yaml:"chanSize"`
21+
InnerLogPath string `yaml:"innerLogPath"`
22+
InnerLogEncode string `yaml:"innerLogEncode"`
23+
}
24+
25+
type variableConfig struct {
26+
Name string `yaml:"name"`
27+
Value string `yaml:"value"`
28+
}
29+
30+
type targetList struct {
31+
File []fileTargetConfig `yaml:"file"`
32+
Udp []udpTargetConfig `yaml:"udp"`
33+
Http []httpTargetConfig `yaml:"http"`
34+
EMail []emailTargetConfig `yaml:"email"`
35+
Fmt []fmtTargetConfig `yaml:"fmt"`
36+
}
37+
38+
type fileTargetConfig struct {
39+
Name string `yaml:"name"`
40+
IsLog bool `yaml:"isLog"`
41+
Layout string `yaml:"layout"`
42+
Encode string `yaml:"encode"`
43+
FileMaxSize int64 `yaml:"fileMaxSize"`
44+
FileName string `yaml:"fileName"`
45+
}
46+
47+
type udpTargetConfig struct {
48+
Name string `yaml:"name"`
49+
IsLog bool `yaml:"isLog"`
50+
Layout string `yaml:"layout"`
51+
Encode string `yaml:"encode"`
52+
RemoteIP string `yaml:"remoteIP"`
53+
}
54+
55+
type httpTargetConfig struct {
56+
Name string `yaml:"name"`
57+
IsLog bool `yaml:"isLog"`
58+
Layout string `yaml:"layout"`
59+
Encode string `yaml:"encode"`
60+
HttpUrl string `yaml:"httpUrl"`
61+
}
62+
63+
type emailTargetConfig struct {
64+
Name string `yaml:"name"`
65+
IsLog bool `yaml:"isLog"`
66+
Layout string `yaml:"layout"`
67+
Encode string `yaml:"encode"`
68+
MailServer string `yaml:"mailServer"`
69+
MailAccount string `yaml:"mailAccount"`
70+
MailNickName string `yaml:"mailNickName"`
71+
MailPassword string `yaml:"mailPassword"`
72+
ToMail string `yaml:"toMail"`
73+
Subject string `yaml:"subject"`
74+
}
75+
76+
type fmtTargetConfig struct {
77+
Name string `yaml:"name"`
78+
IsLog bool `yaml:"isLog"`
79+
Layout string `yaml:"layout"`
80+
Encode string `yaml:"encode"`
81+
}
82+
83+
type loggerConfig struct {
84+
Name string `yaml:"name"`
85+
IsLog bool `yaml:"isLog"`
86+
Layout string `yaml:"layout"`
87+
ConfigMode string `yaml:"configMode"`
88+
Levels []loggerLevelConfig `yaml:"levels"`
89+
}
90+
91+
type loggerLevelConfig struct {
92+
Level string `yaml:"level"`
93+
Targets string `yaml:"targets"`
94+
IsLog bool `yaml:"isLog"`
95+
}
96+
97+
// LoadYamlConfig loads configuration from YAML file
98+
func LoadYamlConfig(configFile string) (*AppConfig, error) {
99+
data, err := os.ReadFile(configFile)
100+
if err != nil {
101+
return nil, fmt.Errorf("failed to read config file: %w", err)
102+
}
103+
104+
var yc yamlConfig
105+
if err := yaml.Unmarshal(data, &yc); err != nil {
106+
return nil, fmt.Errorf("failed to parse YAML config: %w", err)
107+
}
108+
109+
// Convert YAML config to AppConfig
110+
appConfig := &AppConfig{
111+
Global: &GlobalConfig{
112+
IsLog: yc.Global.IsLog,
113+
ChanSize: yc.Global.ChanSize,
114+
InnerLogPath: yc.Global.InnerLogPath,
115+
InnerLogEncode: yc.Global.InnerLogEncode,
116+
},
117+
Variables: make([]*VariableConfig, len(yc.Variables)),
118+
Loggers: make([]*LoggerConfig, len(yc.Loggers)),
119+
Targets: &TargetList{
120+
FileTargets: make([]*FileTargetConfig, len(yc.Targets.File)),
121+
UdpTargets: make([]*UdpTargetConfig, len(yc.Targets.Udp)),
122+
HttpTargets: make([]*HttpTargetConfig, len(yc.Targets.Http)),
123+
EMailTargets: make([]*EMailTargetConfig, len(yc.Targets.EMail)),
124+
FmtTargets: make([]*FmtTargetConfig, len(yc.Targets.Fmt)),
125+
},
126+
}
127+
128+
// Convert variables
129+
for i, v := range yc.Variables {
130+
appConfig.Variables[i] = &VariableConfig{Name: v.Name, Value: v.Value}
131+
}
132+
133+
// Convert loggers
134+
for i, l := range yc.Loggers {
135+
levels := make([]*LoggerLevelConfig, len(l.Levels))
136+
for j, level := range l.Levels {
137+
levels[j] = &LoggerLevelConfig{
138+
Level: level.Level,
139+
Targets: level.Targets,
140+
IsLog: level.IsLog,
141+
}
142+
}
143+
appConfig.Loggers[i] = &LoggerConfig{
144+
Name: l.Name,
145+
IsLog: l.IsLog,
146+
Layout: l.Layout,
147+
ConfigMode: l.ConfigMode,
148+
Levels: levels,
149+
}
150+
}
151+
152+
// Convert file targets
153+
for i, t := range yc.Targets.File {
154+
appConfig.Targets.FileTargets[i] = &FileTargetConfig{
155+
Name: t.Name,
156+
IsLog: t.IsLog,
157+
Layout: t.Layout,
158+
Encode: t.Encode,
159+
FileMaxSize: t.FileMaxSize,
160+
FileName: t.FileName,
161+
}
162+
}
163+
164+
// Convert UDP targets
165+
for i, t := range yc.Targets.Udp {
166+
appConfig.Targets.UdpTargets[i] = &UdpTargetConfig{
167+
Name: t.Name,
168+
IsLog: t.IsLog,
169+
Layout: t.Layout,
170+
Encode: t.Encode,
171+
RemoteIP: t.RemoteIP,
172+
}
173+
}
174+
175+
// Convert HTTP targets
176+
for i, t := range yc.Targets.Http {
177+
appConfig.Targets.HttpTargets[i] = &HttpTargetConfig{
178+
Name: t.Name,
179+
IsLog: t.IsLog,
180+
Layout: t.Layout,
181+
Encode: t.Encode,
182+
HttpUrl: t.HttpUrl,
183+
}
184+
}
185+
186+
// Convert Email targets
187+
for i, t := range yc.Targets.EMail {
188+
appConfig.Targets.EMailTargets[i] = &EMailTargetConfig{
189+
Name: t.Name,
190+
IsLog: t.IsLog,
191+
Layout: t.Layout,
192+
Encode: t.Encode,
193+
MailServer: t.MailServer,
194+
MailAccount: t.MailAccount,
195+
MailNickName: t.MailNickName,
196+
MailPassword: t.MailPassword,
197+
ToMail: t.ToMail,
198+
Subject: t.Subject,
199+
}
200+
}
201+
202+
// Convert Fmt targets
203+
for i, t := range yc.Targets.Fmt {
204+
appConfig.Targets.FmtTargets[i] = &FmtTargetConfig{
205+
Name: t.Name,
206+
IsLog: t.IsLog,
207+
Layout: t.Layout,
208+
Encode: t.Encode,
209+
}
210+
}
211+
212+
return appConfig, nil
213+
}

0 commit comments

Comments
 (0)