Compare commits

..

No commits in common. "master" and "set-syslog-fmt" have entirely different histories.

12 changed files with 55 additions and 207 deletions

2
.gitignore vendored
View file

@ -1,2 +0,0 @@
.*.vim
/build

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "vendor/gopkg.in/mcuadros/go-syslog.v2"]
path = vendor/gopkg.in/mcuadros/go-syslog.v2
url = https://github.com/boyska/go-syslog

View file

@ -54,8 +54,8 @@ func (b *BoolAuto) Set(s string) error {
}
func main() {
queryAddr := flag.String("addr", "", "http service address")
querySocket := flag.String("socket", "/tmp/circologd-query.sock", "Path to a unix domain socket for the HTTP server")
addr := flag.String("addr", "localhost:9080", "http service address")
querySocket := flag.String("socket", "", "Path to a unix domain socket for the HTTP server")
backlogLimit := flag.Int("n", -1, "Limit the backlog length, defaults to no limit (-1)")
var format formatter.Format
format = formatter.FormatSyslog
@ -75,7 +75,7 @@ func main() {
signal.Notify(interrupt, os.Interrupt)
var d *websocket.Dialer
u := url.URL{Scheme: "ws",
Host: *queryAddr, // ignored in case of -socket; see the Dialer below
Host: *addr, // ignored in case of -socket; see the Dialer below
Path: "/ws",
}
q := u.Query()
@ -84,7 +84,7 @@ func main() {
q.Set("l", strconv.Itoa(*backlogLimit))
}
u.RawQuery = q.Encode()
if *queryAddr == "" {
if *querySocket != "" {
d = &websocket.Dialer{
NetDial: func(network, addr string) (net.Conn, error) {
return net.Dial("unix", *querySocket)
@ -95,7 +95,7 @@ func main() {
log.Printf("connecting to %s", *querySocket)
} else {
d = websocket.DefaultDialer
log.Printf("connecting to %s", *queryAddr)
log.Printf("connecting to %s", *addr)
}
c, _, err := d.Dial(u.String(), nil)
@ -149,7 +149,7 @@ func main() {
select {
case <-done:
log.Println("Successfully close")
case <-time.After(5 * time.Second):
case <-time.After(1 * time.Second):
log.Println("Forced close")
}
return

View file

@ -1,39 +0,0 @@
package main
import (
"net"
"github.com/coreos/go-systemd/activation"
)
func Listeners() ([]net.Listener, error) {
files := activation.Files(false)
listeners := make([]net.Listener, len(files))
for i, f := range files {
if pc, err := net.FileListener(f); err == nil {
listeners[i] = pc
f.Close()
}
}
return listeners, nil
}
// PacketConns returns a slice containing a net.PacketConn for each matching socket type
// passed to this process.
//
// The order of the file descriptors is preserved in the returned slice.
// Nil values are used to fill any gaps. For example if systemd were to return file descriptors
// corresponding with "udp, tcp, udp", then the slice would contain {net.PacketConn, nil, net.PacketConn}
func PacketConns() ([]net.PacketConn, error) {
files := activation.Files(false)
conns := make([]net.PacketConn, len(files))
for i, f := range files {
if pc, err := net.FilePacketConn(f); err == nil {
conns[i] = pc
f.Close()
}
}
return conns, nil
}

View file

@ -153,15 +153,6 @@ func getWSHandler(hub circolog.Hub) http.HandlerFunc {
hub.Unregister <- c
conn.Close()
}()
go func() {
for {
_, _, err := conn.ReadMessage()
if err != nil {
conn.Close()
return
}
}
}()
for {
select {
case message, ok := <-c.Messages:

View file

@ -17,29 +17,22 @@ import (
syslog "gopkg.in/mcuadros/go-syslog.v2"
)
var socketsToRemove []string
func cleanSocket(socket string) {
if err := os.Remove(socket); err != nil {
fmt.Fprintln(os.Stderr, "Error cleaning", socket, ":", err)
}
}
func removeAtExit(socket string) {
socketsToRemove = append(socketsToRemove, socket)
}
func main() {
var err error
var syslogSocket SyslogSocket
var logFmt formatter.SyslogRFC
logFmt.Format = syslog.Automatic
flag.Var(&syslogSocket, "syslogd-socket", "The socket to listen to syslog addresses")
logFmt = formatter.Auto
syslogSocketPath := flag.String("syslogd-socket", "", "The socket to listen to syslog addresses")
// dumpSocketPath := flag.String("dump-socket", "/run/buffer.sock", "The socket that user will connect to in order to receive logs")
bufsize := flag.Int("buffer-size", 1000, "Number of messages to keep")
syslogAddr := flag.String("syslog-addr", "127.0.0.1:9514", "Address:port where to listen for syslog messages")
queryAddr := flag.String("query-addr", "", "Address:port where to bind the query service")
querySocket := flag.String("query-socket", "/tmp/circologd-query.sock", "Path to a unix domain socket for the HTTP server; recommended for security reasons!")
queryAddr := flag.String("query-addr", "127.0.0.1:9080", "Address:port where to bind the query service")
querySocket := flag.String("query-socket", "", "Path to a unix domain socket for the HTTP server; recommended for security reasons!")
ctlSocket := flag.String("ctl-socket", "/tmp/circologd-ctl.sock", "Path to a unix domain socket for the control server; leave empty to disable")
flag.Var(&logFmt, "log-fmt", "Log messages format. If not set, defaults to automatic choice. Allowed values: rfc3164, rfc5424, auto.")
verbose := flag.Bool("verbose", false, "Print more output executing the daemon")
@ -54,33 +47,20 @@ func main() {
go hub.Run()
server := syslog.NewServer()
server.SetFormat(logFmt.Format)
fmt.Printf("Syslog format set to: %s\n", logFmt.String())
formatter.SetSyslogFormat(server, logFmt)
server.SetHandler(handler)
if syslogSocket.isSocketActivated {
fmt.Printf("Binding to socket `%s` [syslog]\n", syslogSocket.String())
if syslogSocket.Listener != nil {
fmt.Println("(stream)")
server.Listen(syslogSocket.Listener)
} else {
fmt.Println("(datagram)", syslogSocket.Conn)
server.ListenDgram(syslogSocket.Conn)
if *syslogSocketPath != "" {
if err = server.ListenUnixgram(*syslogSocketPath); err != nil {
fmt.Fprintln(os.Stderr, "argh", err)
os.Exit(1)
}
defer cleanSocket(*syslogSocketPath)
fmt.Printf("Binding socket `%s` [syslog]\n", *syslogSocketPath)
} else {
syslogSocketPath := syslogSocket.Path
if syslogSocketPath != "" {
if err = server.ListenUnixgram(syslogSocketPath); err != nil {
fmt.Fprintln(os.Stderr, "argh", err)
os.Exit(1)
}
fmt.Printf("Binding socket `%s` [syslog]\n", syslogSocketPath)
removeAtExit(syslogSocketPath)
} else {
fmt.Printf("Binding address `%s` [syslog]\n", *syslogAddr)
if err = server.ListenUDP(*syslogAddr); err != nil {
fmt.Fprintln(os.Stderr, "argh", err)
os.Exit(1)
}
fmt.Printf("Binding address `%s` [syslog]\n", *syslogAddr)
if err = server.ListenUDP(*syslogAddr); err != nil {
fmt.Fprintln(os.Stderr, "argh", err)
os.Exit(1)
}
}
if err = server.Boot(); err != nil {
@ -89,14 +69,14 @@ func main() {
}
httpQueryServer := http.Server{Handler: setupHTTP(hub)}
if *queryAddr == "" {
if *querySocket != "" {
fmt.Printf("Binding address `%s` [http]\n", *querySocket)
unixListener, err := net.Listen("unix", *querySocket)
if err != nil {
fmt.Fprintln(os.Stderr, "Error binding HTTP unix domain socket", err)
return
}
removeAtExit(*querySocket)
defer cleanSocket(*querySocket)
go func() {
if err := httpQueryServer.Serve(unixListener); err != nil && err != http.ErrServerClosed {
fmt.Fprintln(os.Stderr, "error binding", *querySocket, ":", err)
@ -121,7 +101,7 @@ func main() {
fmt.Fprintln(os.Stderr, "Error binding HTTP unix domain socket", err)
return
}
removeAtExit(*ctlSocket)
defer cleanSocket(*ctlSocket)
go func() {
if err := httpCtlServer.Serve(unixListener); err != nil && err != http.ErrServerClosed {
fmt.Fprintln(os.Stderr, "error binding:", err)
@ -171,9 +151,6 @@ func main() {
if err := httpCtlServer.Shutdown(nil); err != nil {
fmt.Fprintln(os.Stderr, "Error closing control server:", err)
}
for _, socket := range socketsToRemove {
cleanSocket(socket)
}
return
}
}

View file

@ -1,50 +0,0 @@
package main
import (
"net"
)
// SyslogSocket is a struct eventually containing a net.Listener
// ready with messages, and a Path in case the Listener is not present.
type SyslogSocket struct {
Listener net.Listener
Conn net.PacketConn
Path string
isSocketActivated bool
}
// Set from command-line
func (s *SyslogSocket) Set(v string) error {
err := s.getActivationSocket()
if err == nil && (s.Conn != nil || s.Listener != nil) {
s.isSocketActivated = true
}
if !s.isSocketActivated {
s.Path = v
}
return nil
}
func (s *SyslogSocket) String() string {
if s.isSocketActivated {
return "systemd-provided"
}
return s.Path
}
func (s *SyslogSocket) getActivationSocket() error {
conns, err := PacketConns()
if err == nil && len(conns) > 0 && conns[0] != nil {
s.Conn = conns[0]
return nil
}
listeners, err := Listeners()
if err != nil {
return err
}
if len(listeners) == 0 {
return nil
}
s.Listener = listeners[0]
return nil
}

View file

@ -69,26 +69,4 @@ Here is a working unit for this:
### journald with socket activation
To run circologd as non-root, while listening on a root-owned socket (`/run/systemd/journal/syslog`) use
socket activation. Create a unit in `/etc/systemd/system/circolog.service`:
[Unit]
Description=In-memory logging
[Service]
User=nobody
Group=nogroup
ExecStart=/usr/local/sbin/circologd -syslogd-socket "" -buffer-size 2000 -query-socket /run/circolog/query.sock
[Install]
WantedBy=multi-user.target
Then symlink the `syslog.service` unit to the newly created one:
ln -sf /etc/systemd/system/circolog.service /etc/systemd/system/syslog.service
and restart the service:
systemctl daemon-reload
systemctl restart syslog.service
Now circolog is activated and receives messages from `journald`.
socket activation

View file

@ -4,6 +4,5 @@ nav:
- Install: install.md
- Queries: query.md
- Hacking: hacking.md
- Systemd: systemd.md
repo_url: https://git.lattuga.net/boyska/circolog
repo_name: 'Repository'

View file

@ -2,48 +2,66 @@ package formatter
import (
"errors"
"log"
syslog "gopkg.in/mcuadros/go-syslog.v2"
"gopkg.in/mcuadros/go-syslog.v2/format"
)
// SyslogRFC is the formatter that the server should use
type SyslogRFC struct{ format.Format }
type SyslogRFC string
// SetSyslogFormat does the job of setting the server parser to the provided RFC log format.
func SetSyslogFormat(server *syslog.Server, format SyslogRFC) {
switch {
case format == Auto:
server.SetFormat(syslog.Automatic)
case format == RFC3164:
server.SetFormat(syslog.RFC3164)
case format == RFC5424:
server.SetFormat(syslog.RFC5424)
}
log.Printf("Syslog format set to: %s\n", format)
}
func (rfc *SyslogRFC) Set(v string) error {
newval, err := parseRFCValue(v)
if err != nil {
return err
}
rfc.Format = newval
*rfc = newval
return nil
}
func (rfc *SyslogRFC) String() string {
switch {
case rfc.Format == syslog.Automatic:
case *rfc == Auto:
return "auto"
case rfc.Format == syslog.RFC3164:
case *rfc == RFC3164:
return "rfc3164"
case rfc.Format == syslog.RFC5424:
case *rfc == RFC5424:
return "rfc5424"
}
return ""
}
func parseRFCValue(v string) (format.Format, error) {
func parseRFCValue(v string) (SyslogRFC, error) {
switch {
case v == "rfc3164":
return syslog.RFC3164, nil
return RFC3164, nil
case v == "rfc5424":
return syslog.RFC5424, nil
return RFC5424, nil
case v == "auto":
return syslog.Automatic, nil
return Auto, nil
default:
return nil, ErrRFCNotSupported
return "", ErrRFCNotSupported
}
}
const (
RFC3164 = "rfc3164"
RFC5424 = "rfc5424"
Auto = "auto"
)
// ErrRFCNotSupported is raised if the supplied rfc string is
// not recognized.
var ErrRFCNotSupported = errors.New("RFC not known")

View file

@ -1,20 +0,0 @@
#!/bin/bash
set -u
for goosarch in $(go tool dist list | grep -vw -e aix -e js/wasm -e plan9 -e solaris -e android -e nacl)
do
mkdir -p "build/$goosarch"
goos=$(cut -d/ -f 1 <<<$goosarch)
goarch=$(cut -d/ -f 2 <<<$goosarch)
for cmd in cmd/*; do
GOOS=${goos} GOARCH=${goarch} go build -o "build/$goos/$goarch/$(basename $cmd)" ./$cmd
done
done
find build/ -type f|cut -d/ -f 1-3|uniq|while read -r dir; do
find $dir/ -type f -executable | xargs sha1sum > $dir/SHA1SUMS.txt
# TODO: touch to last commit date maybe
find build -exec touch -d @1234567890 {} \;
zip -q -X -j -r "circolog-$(git describe --tags --always)-$(cut -d/ -f 2-3 <<<"$dir"|tr / -)" "$dir"
done

@ -1 +0,0 @@
Subproject commit 166aad3f993ce4a67bf486e62d637c834c8a8fe6