Alexey Palazhchenko 4c76865d0e
feat: multiple logging improvements
Add JSON over TCP support.
Add support for multiple loggers.
Make logging configurable.

Signed-off-by: Alexey Palazhchenko <alexey.palazhchenko@talos-systems.com>
2021-10-25 16:52:24 +00:00

105 lines
2.4 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package logging
import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
"github.com/talos-systems/talos/pkg/follow"
"github.com/talos-systems/talos/pkg/tail"
)
// FileLoggingManager implements simple logging to files.
type FileLoggingManager struct {
logDirectory string
}
// NewFileLoggingManager initializes new FileLoggingManager.
func NewFileLoggingManager(logDirectory string) *FileLoggingManager {
return &FileLoggingManager{
logDirectory: logDirectory,
}
}
// ServiceLog implements runtime.LoggingManager interface.
func (manager *FileLoggingManager) ServiceLog(id string) runtime.LogHandler {
return &fileLogHandler{
logDirectory: manager.logDirectory,
id: id,
}
}
// SetSenders implements runtime.LoggingManager interface (by doing nothing).
func (manager *FileLoggingManager) SetSenders([]runtime.LogSender) []runtime.LogSender {
return nil
}
type fileLogHandler struct {
path string
logDirectory string
id string
}
func (handler *fileLogHandler) buildPath() error {
if strings.ContainsAny(handler.id, string(os.PathSeparator)+".") {
return fmt.Errorf("service ID is invalid")
}
handler.path = filepath.Join(handler.logDirectory, handler.id+".log")
return nil
}
// Writer implements runtime.LogHandler interface.
func (handler *fileLogHandler) Writer() (io.WriteCloser, error) {
if err := handler.buildPath(); err != nil {
return nil, err
}
return os.OpenFile(handler.path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o666)
}
// Reader implements runtime.LogHandler interface.
func (handler *fileLogHandler) Reader(opts ...runtime.LogOption) (io.ReadCloser, error) {
var opt runtime.LogOptions
for _, o := range opts {
if err := o(&opt); err != nil {
return nil, err
}
}
if err := handler.buildPath(); err != nil {
return nil, err
}
f, err := os.OpenFile(handler.path, os.O_RDONLY, 0)
if err != nil {
return nil, err
}
if opt.TailLines != nil {
err = tail.SeekLines(f, *opt.TailLines)
if err != nil {
f.Close() //nolint:errcheck
return nil, fmt.Errorf("error tailing log: %w", err)
}
}
if opt.Follow {
return follow.NewReader(context.Background(), f), nil
}
return f, nil
}