aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2025-08-13 18:47:49 +0700
committerShulhan <ms@kilabit.info>2025-08-20 02:43:53 +0700
commitf9c0f7d0e73c89b7473b7c0123427b934fcbff65 (patch)
treea91c46b963889e67bc4a0e65ba2ad9829540e72b
parentd34a7d3def91fb614fb657b81ff8265f19e078c8 (diff)
downloadlilin-f9c0f7d0e73c89b7473b7c0123427b934fcbff65.tar.xz
all: store the service logs into file
-rw-r--r--lilin.go3
-rw-r--r--scan_report.go11
-rw-r--r--server.go5
-rw-r--r--server_options.go19
-rw-r--r--service_report.go44
-rw-r--r--service_report_test.go21
-rw-r--r--worker.go27
-rw-r--r--worker_test.go25
8 files changed, 130 insertions, 25 deletions
diff --git a/lilin.go b/lilin.go
index 1febf86..9ebc385 100644
--- a/lilin.go
+++ b/lilin.go
@@ -11,5 +11,8 @@ import (
// defTimeout define default timeout for service and client connection.
const defTimeout = 5 * time.Second
+// defAddress default server address.
+const defAddress = `127.0.0.1:14507`
+
//go:embed _www
var wwwFS embed.FS
diff --git a/scan_report.go b/scan_report.go
index 6544dc7..4b4938d 100644
--- a/scan_report.go
+++ b/scan_report.go
@@ -18,3 +18,14 @@ type ScanReport struct {
// Success is true if service available.
Success bool
}
+
+func (report *ScanReport) toCSV() (record []string) {
+ record = append(record, report.At.String())
+ if report.Success {
+ record = append(record, "true")
+ } else {
+ record = append(record, "false")
+ }
+ record = append(record, report.Error)
+ return record
+}
diff --git a/server.go b/server.go
index ef8fabf..ec6f016 100644
--- a/server.go
+++ b/server.go
@@ -57,7 +57,7 @@ func NewServer(opts ServerOptions) (srv *Server, err error) {
return nil, fmt.Errorf(`%s: %w`, logp, err)
}
- srv.worker, err = newWorker(srv.Options.configDir)
+ srv.worker, err = newWorker(srv.Options)
if err != nil {
return nil, fmt.Errorf(`%s: %w`, logp, err)
}
@@ -86,9 +86,6 @@ func NewServer(opts ServerOptions) (srv *Server, err error) {
func (srv *Server) initFS() (err error) {
if srv.Options.IsDevelopment {
var dirfs = os.DirFS(`_www`)
- if err != nil {
- return err
- }
srv.fs = dirfs.(fs.ReadFileFS)
} else {
var subfs fs.FS
diff --git a/server_options.go b/server_options.go
index 4a033fc..48c47b6 100644
--- a/server_options.go
+++ b/server_options.go
@@ -22,6 +22,12 @@ type ServerOptions struct {
// The BaseDir + "/etc/lilin/".
configDir string
+ // The BaseDir + "/etc/lilin/service.d/".
+ configServiceDir string
+
+ // The BaseDir + "/var/log/lilin/service.d/".
+ logServiceDir string
+
// The address to listen for HTTP server and APIs.
Address string `ini:"server::address"`
@@ -40,6 +46,15 @@ func (opts *ServerOptions) init() (err error) {
}
opts.configDir = filepath.Join(opts.BaseDir, `etc`, `lilin`)
+ opts.configServiceDir = filepath.Join(opts.configDir, `service.d`)
+ opts.logServiceDir = filepath.Join(opts.BaseDir, `var`, `log`, `lilin`, `service.d`)
+
+ err = os.MkdirAll(opts.logServiceDir, 0700)
+ if err != nil {
+ return fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ // Load main configuration.
var cfg = filepath.Join(opts.configDir, `lilin.cfg`)
_, err = os.Stat(cfg)
@@ -57,8 +72,8 @@ func (opts *ServerOptions) init() (err error) {
return fmt.Errorf(`%s: %w`, logp, err)
}
- if opts.Address == "" {
- return fmt.Errorf(`%s: empty Address`, logp)
+ if opts.Address == `` {
+ opts.Address = defAddress
}
return nil
diff --git a/service_report.go b/service_report.go
index 291cd2b..7aee321 100644
--- a/service_report.go
+++ b/service_report.go
@@ -3,6 +3,14 @@
package lilin
+import (
+ "encoding/csv"
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+)
+
// historyKeepSize maximum report to keep in history.
const historyKeepSize = 120
@@ -11,17 +19,44 @@ const historyMax = historyKeepSize * 2
// ServiceReport contains the scan report for single service.
type ServiceReport struct {
+ logf *os.File
+ writer *csv.Writer
+ logPath string
+
Name string
Last ScanReport
History []ScanReport
}
-func NewServiceReport(name string) (svcReport *ServiceReport) {
+func NewServiceReport(opts ServerOptions, name string) (
+ svcReport *ServiceReport, err error,
+) {
+ var logp = `NewServiceReport`
+
svcReport = &ServiceReport{
+ logPath: filepath.Join(opts.logServiceDir, name+`.log`),
Name: name,
History: make([]ScanReport, 0, historyMax),
}
- return svcReport
+
+ svcReport.logf, err = os.OpenFile(svcReport.logPath,
+ os.O_WRONLY|os.O_CREATE, 0600)
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ svcReport.writer = csv.NewWriter(svcReport.logf)
+
+ return svcReport, nil
+}
+
+// Close release any resources opened by report.
+func (svcReport *ServiceReport) Close() (err error) {
+ err = svcReport.logf.Close()
+ if err != nil {
+ return fmt.Errorf(`Close: %w`, err)
+ }
+ return nil
}
func (svcReport *ServiceReport) Store(scanReport ScanReport) {
@@ -32,4 +67,9 @@ func (svcReport *ServiceReport) Store(scanReport ScanReport) {
copy(svcReport.History, svcReport.History[start:])
svcReport.History = svcReport.History[:historyKeepSize-1]
}
+ var record = scanReport.toCSV()
+ var err = svcReport.writer.Write(record)
+ if err != nil {
+ log.Printf(`Store: %s`, err)
+ }
}
diff --git a/service_report_test.go b/service_report_test.go
index 71652f6..95fc27d 100644
--- a/service_report_test.go
+++ b/service_report_test.go
@@ -4,14 +4,31 @@
package lilin
import (
+ "os"
"testing"
"time"
"git.sr.ht/~shulhan/pakakeh.go/lib/test"
)
-func TestServiceReport_push(t *testing.T) {
- var svcReport = NewServiceReport(`test`)
+func TestServiceReport_Store(t *testing.T) {
+ var serverOpts = ServerOptions{
+ BaseDir: `testdata`,
+ }
+ var err = serverOpts.init()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var svcReport *ServiceReport
+ svcReport, err = NewServiceReport(serverOpts, `testStore`)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Cleanup(func() {
+ _ = os.Remove(svcReport.logPath)
+ })
+
var x int64
for x = 1; x <= historyMax+1; x++ {
svcReport.Store(ScanReport{At: time.Unix(x, 0)})
diff --git a/worker.go b/worker.go
index 83f91da..27c78ea 100644
--- a/worker.go
+++ b/worker.go
@@ -4,6 +4,7 @@
package lilin
import (
+ "log"
"os"
"path/filepath"
"strings"
@@ -21,12 +22,12 @@ type worker struct {
Reports Reports
}
-func newWorker(configDir string) (wrk *worker, err error) {
+func newWorker(opts ServerOptions) (wrk *worker, err error) {
wrk = &worker{
Services: make(map[string]*Service),
}
- err = wrk.loadServiceDir(configDir)
+ err = wrk.loadServiceDir(opts)
if err != nil {
return nil, err
}
@@ -35,7 +36,10 @@ func newWorker(configDir string) (wrk *worker, err error) {
Services: make(map[string]*ServiceReport, len(wrk.Services)),
}
for name := range wrk.Services {
- wrk.Reports.Services[name] = NewServiceReport(name)
+ wrk.Reports.Services[name], err = NewServiceReport(opts, name)
+ if err != nil {
+ return nil, err
+ }
}
return wrk, nil
}
@@ -45,11 +49,9 @@ type serviceConfigs struct {
}
// loadServiceDir Load all the service configurations.
-func (wrk *worker) loadServiceDir(configDir string) (err error) {
- var serviceDir = filepath.Join(configDir, `service.d`)
-
+func (wrk *worker) loadServiceDir(opts ServerOptions) (err error) {
var listde []os.DirEntry
- listde, err = os.ReadDir(serviceDir)
+ listde, err = os.ReadDir(opts.configServiceDir)
if err != nil {
return err
}
@@ -69,7 +71,7 @@ func (wrk *worker) loadServiceDir(configDir string) (err error) {
continue
}
- var serviceCfg = filepath.Join(serviceDir, name)
+ var serviceCfg = filepath.Join(opts.configServiceDir, name)
var rawcfg []byte
rawcfg, err = os.ReadFile(serviceCfg)
@@ -124,4 +126,13 @@ func (wrk *worker) stop() {
for _, svc = range wrk.Services {
svc.Stop()
}
+
+ var svcReport *ServiceReport
+ var err error
+ for _, svcReport = range wrk.Reports.Services {
+ err = svcReport.Close()
+ if err != nil {
+ log.Printf(`worker: stop: %s`, err)
+ }
+ }
}
diff --git a/worker_test.go b/worker_test.go
index 46e7cd3..a149b5a 100644
--- a/worker_test.go
+++ b/worker_test.go
@@ -14,18 +14,24 @@ import (
func TestNewWorker(t *testing.T) {
type testCase struct {
expServices map[string]*Service
- configDir string
expError string
+ serverOpts ServerOptions
}
var listCase = []testCase{{
- configDir: `testdata/worker/withoutServiceDir/etc/lilin/`,
- expError: `open testdata/worker/withoutServiceDir/etc/lilin/service.d: no such file or directory`,
+ serverOpts: ServerOptions{
+ BaseDir: `testdata/worker/withoutServiceDir/`,
+ },
+ expError: `open testdata/worker/withoutServiceDir/etc/lilin/service.d: no such file or directory`,
}, {
- configDir: `testdata/worker/readError/etc/lilin/`,
- expError: `open testdata/worker/readError/etc/lilin/service.d/broken.cfg: no such file or directory`,
+ serverOpts: ServerOptions{
+ BaseDir: `testdata/worker/readError/`,
+ },
+ expError: `open testdata/worker/readError/etc/lilin/service.d/broken.cfg: no such file or directory`,
}, {
- configDir: `testdata/etc/lilin/`,
+ serverOpts: ServerOptions{
+ BaseDir: `testdata/`,
+ },
expServices: map[string]*Service{
`example http`: &Service{
opts: ServiceOptions{
@@ -72,7 +78,12 @@ func TestNewWorker(t *testing.T) {
}}
for _, tcase := range listCase {
- wrk, err := newWorker(tcase.configDir)
+ err := tcase.serverOpts.init()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ wrk, err := newWorker(tcase.serverOpts)
if err != nil {
test.Assert(t, ``, tcase.expError, err.Error())
continue