README
ยถ
ezar-logger (EL)
Go ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ๊ฒฝ๋ ์๊ฒฉ ๋ก๊น ํจํค์ง์ ๋๋ค. gRPC ํด๋ผ์ด์ธํธ ์ง์, SHA256 ๊ธฐ๋ฐ ๊ณ ์ ๋ก๊ทธ ID ์์ฑ, Reply ์ฒด์ธ ๊ธฐ๋ฅ, QA ๋ฉ์์ง ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
๐ ์ฃผ์ ๊ธฐ๋ฅ
- gRPC ํด๋ผ์ด์ธํธ: gRPC๋ฅผ ํตํ ์๊ฒฉ ๋ก๊น ์๋น์ค ์ฐ๋
- SHA256 ๊ธฐ๋ฐ ๊ณ ์ ID: ํ์์คํฌํ๋ฅผ ํฌํจํ ๋จ๋ฐฉํฅ ์ํธํ ๋ก๊ทธ ID ์์ฑ
- Reply ์ฒด์ธ ์ง์: Parent ์ฐธ์กฐ๋ฅผ ํตํ ์ฐ๊ด ๋ก๊ทธ ์ฐ๊ฒฐ
- QA ๋ฉ์์ง ์ง์: Channel๊ณผ Managers๋ฅผ ์ง์ ํ QA ์ ์ฉ ๋ก๊ทธ ์ ์ก
- ๋ก๊ทธ ID ๋ฐํ: ๋ชจ๋ ๋ก๊น ํจ์๊ฐ ์์ฑ๋ ๋ก๊ทธ ID ๋ฐํ
- ๋ค์ํ ๋ก๊ทธ ๋ ๋ฒจ: INFO, WARN, ERROR, FATAL, QA ์ง์
- Type & Status: ๋ก๊ทธ ํ์ (MSG/REPLY)๊ณผ ์ํ(PENDING) ์๋ ๊ด๋ฆฌ
- ์คํ ํธ๋ ์ด์ค: ๋๋ฒ๊น ์ ์ํ ๋ด์ฅ ์๋ฌ ์ถ์ ๊ธฐ๋ฅ
- ํ๊ฒฝ๋ณ ๋์: DEV/STAGE/PROD ํ๊ฒฝ์ ๋ฐ๋ฅธ ์๋ ์ค์
- ์๋ TLS: ํ๋ก๋์ ์๋ฒ ์ฐ๊ฒฐ ์ ์๋ TLS ์ ์ฉ
๐ฆ ์ค์น
go get bitbucket.org/ezardev-admin/ezar-logger
๐ง ์๊ตฌ์ฌํญ
- Go 1.24 ์ด์
ezar-grpcv1.18.2 ์ด์- gRPC ๋ก๊น ์๋น์ค ๋คํธ์ํฌ ์ฐ๊ฒฐ
๐ ํ๋ก์ ํธ ๊ตฌ์กฐ
ezar-logger/
โโโ el/ # ๋ฉ์ธ ๋ก๊ฑฐ ํจํค์ง (EL - Ezar Logger)
โ โโโ el.go # ํต์ฌ ๋ก๊น
๊ตฌํ
โ โโโ ql.go # QA ๋ก๊น
๊ตฌํ
โ โโโ el_test.go # ํ
์คํธ ์ฝ๋
โโโ internal/
โ โโโ core/
โ โ โโโ clients/logger/ # gRPC ํด๋ผ์ด์ธํธ
โ โโโ datasource/storage/docs/ # ๋ฐ์ดํฐ ๋ชจ๋ธ
โโโ pkg/utils/ # ์ ํธ๋ฆฌํฐ ํจ์
โโโ example/ # ์ฌ์ฉ ์์
๐ ๋น ๋ฅธ ์์
1. ๋ก๊ฑฐ ์ด๊ธฐํ
package main
import (
"bitbucket.org/ezardev-admin/ezar-logger/el"
)
func main() {
// EL ๋ก๊ฑฐ ์ด๊ธฐํ
// Mode: "PROD" -> ํ๋ก๋์
์๋ฒ, "STAGE" -> ์คํ
์ด์ง ์๋ฒ, ๊ทธ ์ธ -> ๋ก์ปฌ ์ถ๋ ฅ๋ง
el.InitLogger("#my-application", "PROD")
// ๋ก๊น
์์ - ๋ก๊ทธ ID ๋ฐํ
id := el.Info("์ ํ๋ฆฌ์ผ์ด์
์์", "์๋ฒ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์ด๊ธฐํ๋์์ต๋๋ค")
el.Warn("๋์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋", "๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด 85%์
๋๋ค")
el.Error("๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๋ฅ", "์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์คํจ")
}
2. Reply ์ฒด์ธ ์ฌ์ฉ๋ฒ
package main
import (
"bitbucket.org/ezardev-admin/ezar-logger/el"
)
func main() {
el.InitLogger("#order-service", "PROD")
// ์ด๊ธฐ ๋ก๊ทธ ์ ์ก ํ ID ํ๋
parentId := el.Info("์ฃผ๋ฌธ ์์ฑ", "์ ์ฃผ๋ฌธ #12345๊ฐ ์์ฑ๋์์ต๋๋ค")
// ๋ถ๋ชจ ๋ก๊ทธ์ ์ฐ๊ฒฐ๋ Reply ๋ก๊ทธ ์ ์ก
el.ReplyInfo(parentId, "๊ฒฐ์ ์ฒ๋ฆฌ ์ค", "์ฃผ๋ฌธ #12345 ๊ฒฐ์ ๋ฅผ ์ฒ๋ฆฌํ๊ณ ์์ต๋๋ค")
el.ReplyInfo(parentId, "์ฃผ๋ฌธ ์๋ฃ", "์ฃผ๋ฌธ #12345๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋์์ต๋๋ค")
// ๋๋ ์ปค์คํ
๋ ๋ฒจ๋ก Reply
el.Reply(parentId, el.WARN, "์ฌ๊ณ ๋ถ์กฑ", "์ฃผ๋ฌธ ํ ์ฌ๊ณ ๊ฐ ๋ถ์กฑํด์ก์ต๋๋ค")
}
3. QA ๋ฉ์์ง ์ ์ก
package main
import (
"bitbucket.org/ezardev-admin/ezar-logger/el"
)
func main() {
el.InitLogger("#my-service", "PROD")
// QA ๋ฉ์์ง ์ ์ก (์ฑ๋๊ณผ ๋ด๋น์ ์ง์ )
qaId := el.AskQA(
"#qa-channel", // ์ฑ๋
[]string{"manager1", "manager2"}, // ๋ด๋น์ ๋ชฉ๋ก
"๋ฒ๊ทธ ๋ฆฌํฌํธ", // ์ ๋ชฉ
"๊ฒฐ์ ํ์ด์ง์์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค", // ์์ธ ๋ด์ฉ
)
// QA ๋ฉ์์ง์ Reply
el.ReplyQA(
qaId, // ๋ถ๋ชจ QA ๋ก๊ทธ ID
"#qa-channel", // ์ฑ๋
[]string{"manager1"}, // ๋ด๋น์ ๋ชฉ๋ก
"์์ ์๋ฃ", // ์ ๋ชฉ
"๊ฒฐ์ ํ์ด์ง ์ค๋ฅ๋ฅผ ์์ ํ์ต๋๋ค", // ์์ธ ๋ด์ฉ
)
}
4. ๋นํ๋ก๋์ ๋ชจ๋ (๋ก์ปฌ ๊ฐ๋ฐ)
el.InitLogger("#my-app", "DEV") // "PROD" ์ธ์ ๋ชจ๋ ๋ชจ๋
// ์๊ฒฉ ์๋ฒ๋ก ์ ์ก๋์ง ์๊ณ stdout์ ์ถ๋ ฅ๋ฉ๋๋ค
el.Info("ํ
์คํธ", "์ด ๋ฉ์์ง๋ ์ฝ์์ ์ถ๋ ฅ๋ฉ๋๋ค")
// ์ถ๋ ฅ: INFO: ํ
์คํธ ์ด ๋ฉ์์ง๋ ์ฝ์์ ์ถ๋ ฅ๋ฉ๋๋ค
๐ ๋ก๊ทธ ๋ ๋ฒจ
| ๋ ๋ฒจ | ๊ฐ | ์ค๋ช |
|---|---|---|
el.INFO |
0 | ์ ํ๋ฆฌ์ผ์ด์ ํ๋ฆ์ ๋ํ ์ผ๋ฐ ์ ๋ณด |
el.WARN |
1 | ์ ์ฌ์ ๋ฌธ์ ์ ๋ํ ๊ฒฝ๊ณ ๋ฉ์์ง |
el.ERROR |
2 | ์คํจ์ ๋ํ ์ค๋ฅ ๋ฉ์์ง |
el.FATAL |
3 | ์ฌ๊ฐํ ์ค๋ฅ |
el.QA |
4 | QA ๋ฉ์์ง |
๐ ๋ฐ์ดํฐ ๋ชจ๋ธ
LogQue ๊ตฌ์กฐ์ฒด
type LogQue struct {
ID string `json:"_id"` // SHA256 ํด์: #์ฑ์ด๋ฆ-ํด์
AppName string `json:"app_name"` // ์ ํ๋ฆฌ์ผ์ด์
์ด๋ฆ
Title string `json:"title"` // ๋ก๊ทธ ์ ๋ชฉ/์์ฝ
Detail string `json:"detail"` // ์์ธ ๋ก๊ทธ ๋ฉ์์ง
Status string `json:"status"` // ๋ก๊ทธ ์ํ (PENDING)
Type string `json:"type"` // ๋ก๊ทธ ํ์
(MSG/REPLY)
Parent string `json:"parent"` // Reply์ฉ ๋ถ๋ชจ ๋ก๊ทธ ID
Level int `json:"level"` // ๋ก๊ทธ ๋ ๋ฒจ (0-4)
CreatedAt time.Time `json:"created_at"` // ํ์์คํฌํ
}
QaQueue ๊ตฌ์กฐ์ฒด
type QaQueue struct {
*LogQue
Channel string `json:"channel"` // QA ์ฑ๋
Managers []string `json:"managers"` // ๋ด๋น์ ๋ชฉ๋ก
}
๋ก๊ทธ ํ์
| ํ์ | ์ค๋ช |
|---|---|
MSG |
์ผ๋ฐ ๋ก๊ทธ ๋ฉ์์ง |
REPLY |
๊ธฐ์กด ๋ก๊ทธ์ ๋ํ ๋ต๋ณ (๋ถ๋ชจ ์ฐธ์กฐ ํฌํจ) |
๐ง API ๋ ํผ๋ฐ์ค
ํจํค์ง: el
์ด๊ธฐํ
func InitLogger(appName string, mode string)
์ ํ๋ฆฌ์ผ์ด์ ์ด๋ฆ๊ณผ ๋ชจ๋๋ก ์ ์ญ EL ๋ก๊ฑฐ๋ฅผ ์ด๊ธฐํํฉ๋๋ค.
ํ๋ผ๋ฏธํฐ:
appName: ์ ํ๋ฆฌ์ผ์ด์ ์ด๋ฆ (์: "#my-service")mode: ํ๊ฒฝ ๋ชจ๋ ("PROD", "STAGE", ๋๋ ๋ก์ปฌ์ฉ ๊ธฐํ)
๊ธฐ๋ณธ ๋ก๊น ํจ์
func Info(title string, detail string) string
func Warn(title string, detail string) string
func Error(title string, detail string) string
func Send(level LogLevel, title string, detail string) string
๋ชจ๋ ๋ก๊น ํจ์๋ ์์ฑ๋ ๋ก๊ทธ ID๋ฅผ ๋ฐํํฉ๋๋ค.
Reply ํจ์
func ReplyInfo(parent string, title string, detail string) string
func ReplyWarn(parent string, title string, detail string) string
func ReplyError(parent string, title string, detail string) string
func Reply(parent string, level LogLevel, title string, detail string) string
Reply ํจ์๋ ๋ก๊ทธ๋ฅผ ๋ถ๋ชจ ๋ก๊ทธ ID์ ์ฐ๊ฒฐํฉ๋๋ค.
QA ํจ์
func AskQA(channel string, managers []string, title string, detail string) string
func SendQA(level LogLevel, channel string, managers []string, title string, detail string) string
func ReplyQA(parent string, channel string, managers []string, title string, detail string) string
func SendReplyQa(parent string, channel string, managers []string, level LogLevel, title string, detail string) string
QA ํจ์๋ ์ฑ๋๊ณผ ๋ด๋น์๋ฅผ ์ง์ ํ์ฌ QA ์ ์ฉ ๋ฉ์์ง๋ฅผ ์ ์กํฉ๋๋ค.
์ ํธ๋ฆฌํฐ ํจ์
func Trace(err ...error) string
๋๋ฒ๊น ์ ์ํ ์คํ ํธ๋ ์ด์ค ์ ๋ณด๋ฅผ ๋ฐํํฉ๋๋ค.
๐ ๊ณ ์ ๋ก๊ทธ ID ์์ฑ
EL ๋ก๊ฑฐ๋ title:detail:timestamp์ SHA256 ํด์๋ก ๊ณ ์ ID๋ฅผ ์์ฑํฉ๋๋ค:
// ํ์: #์ฑ์ด๋ฆ-ํด์ (SHA256 ์ฒซ 8๋ฐ์ดํธ์ 16์ง์ ๋ฌธ์ 16๊ฐ)
// ์์: #my-service-a1b2c3d4e5f6g7h8
์ฅ์ :
- ๊ณ ์ ์ฑ: ํ์์คํฌํ๋ก ๋์ผํ title+detail๋ ๊ณ ์ ID ๋ณด์ฅ
- ์ถ์ ์ฑ: ์ฑ ์ด๋ฆ ์ ๋์ฌ๋ก ์ฌ์ด ์๋ณ
- ๊ฐ๊ฒฐํจ: 16์ ํด์๋ก ๊ฐ๋ ์ฑ ํ๋ณด
๐ ์๋ฒ ์ค์
| ๋ชจ๋ | ์๋ฒ |
|---|---|
PROD |
ํ๋ก๋์ gRPC ์๋ฒ (์๋ TLS) |
STAGE |
์คํ ์ด์ง gRPC ์๋ฒ (์๋ TLS) |
| ๊ธฐํ | ๋ก์ปฌ stdout๋ง (์๊ฒฉ ์ ์ก ์์) |
๐ฏ ์ฌ์ฉ ์ฌ๋ก
์ ํ๋ฆฌ์ผ์ด์ ๋ชจ๋ํฐ๋ง
id := el.Info("์ฌ์ฉ์ ํ๋", "์ฌ์ฉ์ john.doe๊ฐ IP 192.168.1.100์์ ๋ก๊ทธ์ธํ์ต๋๋ค")
el.ReplyInfo(id, "์ธ์
์์ฑ", "24์๊ฐ ๋ง๋ฃ์ ์ ์ธ์
์ด ์์ฑ๋์์ต๋๋ค")
์ปจํ ์คํธ๊ฐ ์๋ ์ค๋ฅ ์ถ์
errId := el.Error("๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ", "์ฃผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์คํจ")
el.ReplyWarn(errId, "ํด๋ฐฑ ํ์ฑํ", "๋ฐฑ์
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ์ ํ๋์์ต๋๋ค")
el.ReplyInfo(errId, "๋ณต๊ตฌ ์๋ฃ", "์ฃผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ด ๋ณต๊ตฌ๋์์ต๋๋ค")
๋น์ฆ๋์ค ํ๋ก์ธ์ค ์ถ์
orderId := el.Info("์ฃผ๋ฌธ ์์ฑ", "๊ณ ๊ฐ john@example.com์ ์ ์ฃผ๋ฌธ #12345")
el.ReplyInfo(orderId, "๊ฒฐ์ ์์", "๊ฒฐ์ ์ฒ๋ฆฌ๊ฐ ์์๋์์ต๋๋ค")
el.ReplyInfo(orderId, "๊ฒฐ์ ์ฑ๊ณต", "$99.99 ๊ฒฐ์ ๊ฐ ์๋ฃ๋์์ต๋๋ค")
el.ReplyInfo(orderId, "๋ฐฐ์ก", "FedEx ์ด์ก์ฅ #ABC123์ผ๋ก ๋ฐฐ์ก๋์์ต๋๋ค")
QA ์ด์ ์ถ์
qaId := el.AskQA("#bug-report", []string{"dev-team"}, "UI ๋ฒ๊ทธ", "๋ชจ๋ฐ์ผ์์ ๋ฒํผ์ด ํ์๋์ง ์์ต๋๋ค")
el.ReplyQA(qaId, "#bug-report", []string{"dev-team"}, "๋ถ์ ์ค", "์ฌํ ํ๊ฒฝ์ ํ์ธํ๊ณ ์์ต๋๋ค")
el.ReplyQA(qaId, "#bug-report", []string{"dev-team"}, "ํด๊ฒฐ ์๋ฃ", "CSS ์์ ์ผ๋ก ํด๊ฒฐ๋์์ต๋๋ค")
๐งช ํ ์คํธ
go test ./el -v
๐ Python ํจํค์ง
ezar-logger๋ Python์์๋ ๋์ผํ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ค์น (uv ์ฌ์ฉ)
# SSH ๋ฐฉ์
uv pip install "ezar-logger @ git+ssh://git@bitbucket.org/ezardev-admin/ezar-logger.git#subdirectory=python"
# HTTPS ๋ฐฉ์
uv pip install "ezar-logger @ git+https://bitbucket.org/ezardev-admin/ezar-logger.git#subdirectory=python"
pyproject.toml ์์กด์ฑ์ผ๋ก ์ถ๊ฐ
dependencies = [
"ezar-logger @ git+ssh://git@bitbucket.org/ezardev-admin/ezar-logger.git#subdirectory=python",
]
Python ์ฌ์ฉ๋ฒ
import ezar_logger as el
# ๋ก๊ฑฐ ์ด๊ธฐํ
el.init_logger("#my-app", "PROD")
# ๊ธฐ๋ณธ ๋ก๊ทธ
log_id = el.info("์์
์์", "๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์์ํฉ๋๋ค")
el.warn("๊ฒฝ๊ณ ", "๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋์ต๋๋ค")
el.error("์ค๋ฅ", "๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์คํจ")
# ์๋ต ๋ก๊ทธ (์ด์ ๋ก๊ทธ์ ์ฐ๊ฒฐ)
el.reply_info(log_id, "์์
์๋ฃ", "100๊ฑด ์ฒ๋ฆฌ ์๋ฃ")
el.reply_warn(log_id, "๋ถ๋ถ ์๋ฃ", "์ผ๋ถ ํญ๋ชฉ ๊ฑด๋๋")
el.reply_error(log_id, "์์
์คํจ", "์ฒ๋ฆฌ ์ค ์ค๋ฅ ๋ฐ์")
# ์๋ฌ ๋ก๊ทธ์ ์คํ ํธ๋ ์ด์ค
try:
raise ValueError("์์ ์ค๋ฅ")
except Exception as e:
el.error("์ค๋ฅ ๋ฐ์", el.trace(e))
# QA ์๋ฆผ (์ฌ๋ ์ฑ๋๊ณผ ๋ด๋น์ ์ง์ )
el.ask_qa("qa-channel", ["@manager1", "@manager2"], "๋ฆฌ๋ทฐ ์์ฒญ", "PR #123 ๊ฒํ ๋ถํ๋๋ฆฝ๋๋ค")
el.reply_qa(log_id, "qa-channel", ["@manager1"], "๋ฆฌ๋ทฐ ์๋ฃ", "์น์ธ๋์์ต๋๋ค")
Python API ๋งคํ
| Go | Python |
|---|---|
el.InitLogger() |
el.init_logger() |
el.Info() |
el.info() |
el.Warn() |
el.warn() |
el.Error() |
el.error() |
el.ReplyInfo() |
el.reply_info() |
el.ReplyWarn() |
el.reply_warn() |
el.ReplyError() |
el.reply_error() |
el.AskQA() |
el.ask_qa() |
el.ReplyQA() |
el.reply_qa() |
el.Trace() |
el.trace() |
์์ธํ Python ์ฌ์ฉ๋ฒ์ python/README.md๋ฅผ ์ฐธ์กฐํ์ธ์.
๐ ์ฑ๋ฅ ํน์ง
- ์ง์ฐ ์ฐ๊ฒฐ: ์ฒซ ๋ก๊ทธ ์ ์ก ์ gRPC ์ฐ๊ฒฐ ์๋ฆฝ
- ์๋ ์ฌ์ฐ๊ฒฐ: ์ฐ๊ฒฐ ๋๊น ์ ์๋ ์ฌ์ฐ๊ฒฐ
- 30์ด ํ์์์: ์์ ์ฑ์ ์ํ ์ค์ ๊ฐ๋ฅํ ํ์์์
- ๋น์ฐจ๋จ ์ค๋ฅ: ์คํจํ ์์ ์ ๋ก์ปฌ์ ๋ก๊น , ์ฑ ํฌ๋์ ์์
๐ ๋ณด์
- ๋จ๋ฐฉํฅ ์ํธํ: ๋ก๊ทธ ID๋ SHA256 ํด์ฑ ์ฌ์ฉ (์ญ์ฐ ๋ถ๊ฐ)
- ์๋ TLS: ํ๋ก๋์ ์๋ฒ(*.ezar.co.kr)์ TLS ์๋ ํ์ฑํ
- ์์ ํ ๋ก๊น : ์คํจํ ์์ ์ stdout์ ๋ก๊น
๐ ๋ณ๊ฒฝ ์ด๋ ฅ
v1.5.0
- QA ๋ก๊ทธ ๋ ๋ฒจ ์ถ๊ฐ
- AskQA, ReplyQA ํจ์ ์ถ๊ฐ (์ฑ๋, ๋ด๋น์ ์ง์ ๊ฐ๋ฅ)
- QaQueue ๊ตฌ์กฐ์ฒด ์ถ๊ฐ (Channel, Managers ํ๋)
- gRPC LogQue ๋ฉ์์ง์ channel, managers ํ๋ ์ง์
- ezar-grpc v1.18.2๋ก ์ ๊ทธ๋ ์ด๋
v1.4.0
- ๋ชจ๋ ๋ก๊น ํจ์(Info, Warn, Error)๊ฐ ๋ก๊ทธ ID ๋ฐํ
v1.3.1
- Parent ํ๋๋ฅผ ํตํ Reply ์ฒด์ธ ์ง์ ์ถ๊ฐ
- Type(MSG/REPLY)๊ณผ Status(PENDING) ํ๋ ์ถ๊ฐ
- ezar-grpc v1.13.3์ผ๋ก ์ ๊ทธ๋ ์ด๋
- UpdateLog ๊ธฐ๋ฅ ์ ๊ฑฐ
v1.3.0
- ์ด๊ธฐ gRPC ํด๋ผ์ด์ธํธ ๊ตฌํ
- SHA256 ๊ธฐ๋ฐ ๊ณ ์ ๋ก๊ทธ ID
- ๋ค์ค ํ๊ฒฝ ์ง์ (PROD/STAGE/DEV)
๐ ๋ผ์ด์ ์ค
์ด ํ๋ก์ ํธ๋ MIT ๋ผ์ด์ ์ค๋ก ์ ๊ณต๋ฉ๋๋ค - ์์ธํ ๋ด์ฉ์ LICENSE ํ์ผ์ ์ฐธ์กฐํ์ธ์.
๐ ์ง์
- Bitbucket์์ ์ด์ ์์ฑ
- ์์ ๋ฐ ํ ์คํธ ํ์ผ ์ฐธ์กฐ
Directories
ยถ
| Path | Synopsis |
|---|---|
|
Package ezarlogger provides a simple and flexible logging utility for Go applications.
|
Package ezarlogger provides a simple and flexible logging utility for Go applications. |
|
internal
|
|
|
pkg
|
|