aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2026-01-21 01:12:11 +0700
committerShulhan <ms@kilabit.info>2026-01-21 01:12:11 +0700
commitfa4cc3a2ae6fa63bfbd8b005e4048dacc222dcc1 (patch)
treeb5566fe088dc51364101ab1db2a48ed845a4d832
parentd0969869954c299c04ea58ab0fda1eba6a0350da (diff)
downloadlilin-fa4cc3a2ae6fa63bfbd8b005e4048dacc222dcc1.tar.xz
all: implement default down and up templates under section "[default"]
To minimize defining the same templates in notification, user can set default down and up templates under the default section.
-rw-r--r--README.md113
-rw-r--r--lilin.go3
-rw-r--r--notif_config.go10
-rw-r--r--notif_config_test.go3
-rw-r--r--server_config.go27
-rw-r--r--server_config_test.go11
6 files changed, 114 insertions, 53 deletions
diff --git a/README.md b/README.md
index 3fbc094..dcb93dd 100644
--- a/README.md
+++ b/README.md
@@ -9,9 +9,10 @@ Lilin is service monitoring for HTTP and TCP services.
Features,
-- Monitoring HTTP, TCP, UDP services
+- Monitoring HTTP and TCP services
- Sending notification when service up or down through,
- Mattermost incoming webhook
+ - SMTP server (email)
## Building
@@ -25,7 +26,9 @@ to build the program,
The above command will create executable file named `lilin` in the current
directory.
-## Command options
+## Usage
+
+### Command options
The lilin program has the following options,
@@ -33,7 +36,7 @@ The lilin program has the following options,
service configurations, and storing the service logs.
If not defined, its default to "/".
-## Main configuration
+### Main configuration
Lilin read the main configuration from `${BASEDIR}etc/lilin/lilin.cfg`.
The configuration is written in
@@ -48,17 +51,52 @@ For example,
The `lilin.cfg` has the following format,
```
+[default]
+down_template = Service {{.ID}} is down: {{.Error}}
+up_template = Service {{.ID}} is alive!
+
[server]
-address =
+address = 127.0.0.1:14507
+```
+
+The `[default]` section define the default value for common configuration.
+
+The `down_template` and `up_template` define the text template to be send
+for notification when the service down or up.
+If its empty, it will use the default one (as written above).
+The `down_template` and `up_template` can contains the following variables,
+
+- .ID: the service ID
+- .At: the time when service up or down
+- .Error: the error message that cause the service marked as down
+
+For example, given the following scan report value,
+
+```
+.ID: http-server
+.At: 2025-09-26 06:38:11 +0000 UTC
+.Error: 503 Service Unavailable
+```
+
+The following `down_template`
+
+```
+{{.At}}: Service {{.ID}} is down: {{.Error}}
+```
+
+will be rendered as
+
+```
+2025-09-26 06:38:11 +0000 UTC: Service http-server is down: 503 Service Unavailable
```
-**address**:: define the HTTP server address to view the status of monitored
-services from web browser, default to 127.0.0.1:14507.
+The server `address` define the HTTP server address to view the status
+of monitored services from web browser, default to 127.0.0.1:14507.
-## Monitoring services
+### Monitoring services
Lilin monitor the services by reading each service configuration inside the
-`${BASEDIR}etc/lilin/service.d/` directory.
+`${BASEDIR}/etc/lilin/service.d/` directory.
Each service configuration is written in INI file format and must have
`.cfg` file extension.
@@ -81,7 +119,6 @@ For example
- `http://example.com/health` for monitoring HTTP service,
- `https://example.com:8443/health` for monitoring HTTPS service,
- `tcp://127.0.0.1:22` for monitoring TCP service,
-- `udp://127.0.0.1:53` for monitoring UDP service.
**method**:: The HTTP method to be used to inquiry the HTTP or HTTPS
service, default to GET.
@@ -111,7 +148,7 @@ interval = 5m
timeout = 60s
```
-Sample of service configuration that monitor TCP service at
+Example of service configuration that monitor TCP service at
127.0.0.1:5432 every 90 seconds with 30 seconds timeout,
```
@@ -124,11 +161,16 @@ timeout = 30s
## Notification
+Lilin send the down notification when the service check failed three times
+consecutively.
+
Lilin support sending notification to,
- Mattermost using incoming webhook.
- SMTP server (email).
+Each notification can have their own `down_template` and `up_template`.
+
See the next section on how to use the notification.
### Mattermost incoming webhook
@@ -147,32 +189,6 @@ down_template = # Message template when service is down.
up_template = # Message template when service is up.
```
-The `down_template` and `up_template` can contains the following variables,
-
-- .ID: the service ID
-- .At: the time when service up or down
-- .Error: the error message that cause the service marked as down
-
-For example, given the following scan report value,
-
-```
-.ID: http-server
-.At: 2025-09-26 06:38:11 +0000 UTC
-.Error: 503 Service Unavailable
-```
-
-The following `down_template`
-
-```
-{{.At}}: Service {{.ID}} is down: {{.Error}}
-```
-
-will be rendered as
-
-```
-2025-09-26 06:38:11 +0000 UTC: Service http-server is down: 503 Service Unavailable
-```
-
<!--}}}-->
### SMTP server
@@ -183,9 +199,11 @@ will be rendered as
[notif]
kind = smtp
remote_url = <scheme "://" (domain | ip_address [":" port])>
-user =
-password =
-recipient =
+user = # Sender email address.
+password = # Sender SMTP password for authentication.
+recipient = # Email address that receive notification.
+down_template = # Custom text to be send when service down.
+up_template = # Custom text to be send when service up.
```
The `remote_url` define the SMTP server address.
@@ -194,27 +212,26 @@ The scheme in `remote_url` can be set either to,
- smtps: implicit TLS, connect to port 465 by default
- smtp+starttls: explicit STARTTLS, connect to port 587 by default.
-The `user` field define the sender email address.
+The `recipient` field can be defined multiple times.
-The `password` field define the password for authentication, on behalf of
-the `user`.
+<!--}}}-->
-The `recipient` is the email address that will receives the notification.
-This field can be defined multiple times.
+## License
-<!--}}}-->
+Lilin is licensed under GPL version 3.0.
+See LICENSE file for more information.
## Links
[Project page](https://sr.ht/~shulhan/lilin).
-[Repository](https://git.sr.ht/~shulhan/lilin) --
+[Repository](https://git.sr.ht/~shulhan/lilin) -
The repository of this software project.
-[Mailing list](https://lists.sr.ht/~shulhan/lilin) --
+[Mailing list](https://lists.sr.ht/~shulhan/lilin) -
Place for discussion and sending patches.
-[Issues](https://todo.sr.ht/~shulhan/lilin) --
+[Issues](https://todo.sr.ht/~shulhan/lilin) -
Place to open new issue or request for new feature.
[Changelog](https://kilabit.info/project/lilin/CHANGELOG.html) - Log for
diff --git a/lilin.go b/lilin.go
index b855692..70ce678 100644
--- a/lilin.go
+++ b/lilin.go
@@ -17,5 +17,8 @@ const defTimeout = 5 * time.Second
// defAddress default server address.
const defAddress = `127.0.0.1:14507`
+const defaultDownTemplate = `Service {{.ID}} is down: {{.Error}}`
+const defaultUpTemplate = `Service {{.ID}} is alive!`
+
//go:embed _www
var wwwFS embed.FS
diff --git a/notif_config.go b/notif_config.go
index c3ed43c..ca1a66b 100644
--- a/notif_config.go
+++ b/notif_config.go
@@ -43,7 +43,7 @@ type NotifConfig struct {
Recipient []string `ini:"notif::recipient"`
}
-func (notifConfig *NotifConfig) init() (err error) {
+func (notifConfig *NotifConfig) init(cfg *ServerConfig) (err error) {
var logp = `notifConfig.init`
switch notifConfig.Kind {
@@ -66,7 +66,9 @@ func (notifConfig *NotifConfig) init() (err error) {
default:
return fmt.Errorf(`%s: unknown notif kind %q`, logp, notifConfig.Kind)
}
- if notifConfig.DownTemplate != "" {
+ if notifConfig.DownTemplate == `` {
+ notifConfig.downTmpl = cfg.downTmpl
+ } else {
notifConfig.downTmpl = template.New(`down`)
notifConfig.downTmpl, err = notifConfig.downTmpl.Parse(notifConfig.DownTemplate)
if err != nil {
@@ -74,7 +76,9 @@ func (notifConfig *NotifConfig) init() (err error) {
logp, notifConfig.Kind, err)
}
}
- if notifConfig.UpTemplate != "" {
+ if notifConfig.UpTemplate == `` {
+ notifConfig.upTmpl = cfg.upTmpl
+ } else {
notifConfig.upTmpl = template.New(`up`)
notifConfig.upTmpl, err = notifConfig.upTmpl.Parse(notifConfig.UpTemplate)
if err != nil {
diff --git a/notif_config_test.go b/notif_config_test.go
index b7990b1..4c63e60 100644
--- a/notif_config_test.go
+++ b/notif_config_test.go
@@ -41,8 +41,9 @@ func TestNotifConfig_init(t *testing.T) {
},
},
}}
+ cfg := &ServerConfig{}
for _, tc := range listCase {
- err := tc.config.init()
+ err := tc.config.init(cfg)
if err != nil {
test.Assert(t, ``, tc.expError, err.Error())
continue
diff --git a/server_config.go b/server_config.go
index c9c553c..2a320a2 100644
--- a/server_config.go
+++ b/server_config.go
@@ -5,6 +5,7 @@ package lilin
import (
"fmt"
+ "html/template"
"os"
"path/filepath"
@@ -13,6 +14,9 @@ import (
// ServerConfig define the options for Lilin Server.
type ServerConfig struct {
+ downTmpl *template.Template
+ upTmpl *template.Template
+
// BaseDir define the base directory for running the server, default
// to "/".
// Its affect where to read the configuration, storing states, and
@@ -28,6 +32,9 @@ type ServerConfig struct {
// The BaseDir + "/var/log/lilin/service.d/".
logServiceDir string
+ DownTemplate string `ini:"default::down_template"`
+ UpTemplate string `ini:"default::up_template"`
+
// The address to listen for HTTP server and APIs.
Address string `ini:"server::address"`
@@ -78,8 +85,26 @@ func (cfg *ServerConfig) init() (err error) {
cfg.Address = defAddress
}
+ if cfg.DownTemplate == `` {
+ cfg.DownTemplate = defaultDownTemplate
+ }
+ cfg.downTmpl = template.New(`down`)
+ cfg.downTmpl, err = cfg.downTmpl.Parse(cfg.DownTemplate)
+ if err != nil {
+ return fmt.Errorf(`%s: failed to parse down_template: %s`, logp, err)
+ }
+
+ if cfg.UpTemplate == `` {
+ cfg.UpTemplate = defaultUpTemplate
+ }
+ cfg.upTmpl = template.New(`up`)
+ cfg.upTmpl, err = cfg.upTmpl.Parse(cfg.DownTemplate)
+ if err != nil {
+ return fmt.Errorf(`%s: failed to parse down_template: %s`, logp, err)
+ }
+
for _, notifConfig := range cfg.Notifs {
- err = notifConfig.init()
+ err = notifConfig.init(cfg)
if err != nil {
return fmt.Errorf(`%s: %w`, logp, err)
}
diff --git a/server_config_test.go b/server_config_test.go
index bd17b5e..56542d6 100644
--- a/server_config_test.go
+++ b/server_config_test.go
@@ -37,6 +37,8 @@ func TestServerConfig_init(t *testing.T) {
configServiceDir: `testdata/server_config/ok/etc/lilin/service.d`,
logServiceDir: `testdata/server_config/ok/var/log/lilin/service.d`,
Address: `127.0.0.1:12121`,
+ DownTemplate: defaultDownTemplate,
+ UpTemplate: defaultUpTemplate,
Notifs: []*NotifConfig{{
Kind: `mattermost`,
RemoteURL: `http://127.0.0.1:12000`,
@@ -76,6 +78,15 @@ func TestServerConfig_init(t *testing.T) {
t.Fatal(err)
}
+ if cfg.upTmpl == nil {
+ t.Fatal(`ServerConfig: got nil on upTmpl, want not-nil`)
+ }
+ if cfg.downTmpl == nil {
+ t.Fatal(`ServerConfig: got nil on downTmpl, want not-nil`)
+ }
+ cfg.upTmpl = nil
+ cfg.downTmpl = nil
+
for x, notifCfg := range cfg.Notifs {
if notifCfg.upTmpl == nil {
t.Fatalf(`ServerConfig.Notifs #%d: upTmpl is nil`, x)