mirror of
https://github.com/netbirdio/netbird.git
synced 2025-08-10 23:55:47 +02:00
client: container: support CLI with entrypoint addition (#4126)
This will allow running netbird commands (including debugging) against the daemon and provide a flow similar to non-container usages. It will by default both log to file and stderr so it can be handled more uniformly in container-native environments.
This commit is contained in:
committed by
GitHub
parent
3f82698089
commit
af8687579b
3
.dockerignore-client
Normal file
3
.dockerignore-client
Normal file
@ -0,0 +1,3 @@
|
||||
*
|
||||
!client/netbird-entrypoint.sh
|
||||
!netbird
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -30,3 +30,4 @@ infrastructure_files/setup-*.env
|
||||
.vscode
|
||||
.DS_Store
|
||||
vendor/
|
||||
/netbird
|
||||
|
@ -155,13 +155,15 @@ dockers:
|
||||
goarch: amd64
|
||||
use: buildx
|
||||
dockerfile: client/Dockerfile
|
||||
extra_files:
|
||||
- client/netbird-entrypoint.sh
|
||||
build_flag_templates:
|
||||
- "--platform=linux/amd64"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
- "--label=org.opencontainers.image.title={{.ProjectName}}"
|
||||
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||
- "--label=org.opencontainers.image.source=https://github.com/netbirdio/{{.ProjectName}}"
|
||||
- "--label=maintainer=dev@netbird.io"
|
||||
- image_templates:
|
||||
- netbirdio/netbird:{{ .Version }}-arm64v8
|
||||
@ -171,6 +173,8 @@ dockers:
|
||||
goarch: arm64
|
||||
use: buildx
|
||||
dockerfile: client/Dockerfile
|
||||
extra_files:
|
||||
- client/netbird-entrypoint.sh
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm64"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
@ -188,6 +192,8 @@ dockers:
|
||||
goarm: 6
|
||||
use: buildx
|
||||
dockerfile: client/Dockerfile
|
||||
extra_files:
|
||||
- client/netbird-entrypoint.sh
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
@ -205,6 +211,8 @@ dockers:
|
||||
goarch: amd64
|
||||
use: buildx
|
||||
dockerfile: client/Dockerfile-rootless
|
||||
extra_files:
|
||||
- client/netbird-entrypoint.sh
|
||||
build_flag_templates:
|
||||
- "--platform=linux/amd64"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
@ -221,6 +229,8 @@ dockers:
|
||||
goarch: arm64
|
||||
use: buildx
|
||||
dockerfile: client/Dockerfile-rootless
|
||||
extra_files:
|
||||
- client/netbird-entrypoint.sh
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm64"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
@ -238,6 +248,8 @@ dockers:
|
||||
goarm: 6
|
||||
use: buildx
|
||||
dockerfile: client/Dockerfile-rootless
|
||||
extra_files:
|
||||
- client/netbird-entrypoint.sh
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm"
|
||||
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||
|
@ -1,9 +1,27 @@
|
||||
FROM alpine:3.21.3
|
||||
# build & run locally with:
|
||||
# cd "$(git rev-parse --show-toplevel)"
|
||||
# CGO_ENABLED=0 go build -o netbird ./client
|
||||
# sudo podman build -t localhost/netbird:latest -f client/Dockerfile --ignorefile .dockerignore-client .
|
||||
# sudo podman run --rm -it --cap-add={BPF,NET_ADMIN,NET_RAW} localhost/netbird:latest
|
||||
|
||||
FROM alpine:3.22.0
|
||||
# iproute2: busybox doesn't display ip rules properly
|
||||
RUN apk add --no-cache ca-certificates ip6tables iproute2 iptables
|
||||
RUN apk add --no-cache \
|
||||
bash \
|
||||
ca-certificates \
|
||||
ip6tables \
|
||||
iproute2 \
|
||||
iptables
|
||||
|
||||
ENV \
|
||||
NETBIRD_BIN="/usr/local/bin/netbird" \
|
||||
NB_LOG_FILE="console,/var/log/netbird/client.log" \
|
||||
NB_DAEMON_ADDR="unix:///var/run/netbird.sock" \
|
||||
NB_ENTRYPOINT_SERVICE_TIMEOUT="5" \
|
||||
NB_ENTRYPOINT_LOGIN_TIMEOUT="1"
|
||||
|
||||
ENTRYPOINT [ "/usr/local/bin/netbird-entrypoint.sh" ]
|
||||
|
||||
ARG NETBIRD_BINARY=netbird
|
||||
COPY ${NETBIRD_BINARY} /usr/local/bin/netbird
|
||||
|
||||
ENV NB_FOREGROUND_MODE=true
|
||||
ENTRYPOINT [ "/usr/local/bin/netbird","up"]
|
||||
COPY client/netbird-entrypoint.sh /usr/local/bin/netbird-entrypoint.sh
|
||||
COPY "${NETBIRD_BINARY}" /usr/local/bin/netbird
|
||||
|
@ -1,18 +1,33 @@
|
||||
FROM alpine:3.21.0
|
||||
# build & run locally with:
|
||||
# cd "$(git rev-parse --show-toplevel)"
|
||||
# CGO_ENABLED=0 go build -o netbird ./client
|
||||
# podman build -t localhost/netbird:latest -f client/Dockerfile --ignorefile .dockerignore-client .
|
||||
# podman run --rm -it --cap-add={BPF,NET_ADMIN,NET_RAW} localhost/netbird:latest
|
||||
|
||||
ARG NETBIRD_BINARY=netbird
|
||||
COPY ${NETBIRD_BINARY} /usr/local/bin/netbird
|
||||
FROM alpine:3.22.0
|
||||
|
||||
RUN apk add --no-cache ca-certificates \
|
||||
RUN apk add --no-cache \
|
||||
bash \
|
||||
ca-certificates \
|
||||
&& adduser -D -h /var/lib/netbird netbird
|
||||
|
||||
WORKDIR /var/lib/netbird
|
||||
USER netbird:netbird
|
||||
|
||||
ENV NB_FOREGROUND_MODE=true
|
||||
ENV NB_USE_NETSTACK_MODE=true
|
||||
ENV NB_ENABLE_NETSTACK_LOCAL_FORWARDING=true
|
||||
ENV NB_CONFIG=config.json
|
||||
ENV NB_DAEMON_ADDR=unix://netbird.sock
|
||||
ENV NB_DISABLE_DNS=true
|
||||
ENV \
|
||||
NETBIRD_BIN="/usr/local/bin/netbird" \
|
||||
NB_USE_NETSTACK_MODE="true" \
|
||||
NB_ENABLE_NETSTACK_LOCAL_FORWARDING="true" \
|
||||
NB_CONFIG="/var/lib/netbird/config.json" \
|
||||
NB_STATE_DIR="/var/lib/netbird" \
|
||||
NB_DAEMON_ADDR="unix:///var/lib/netbird/netbird.sock" \
|
||||
NB_LOG_FILE="console,/var/lib/netbird/client.log" \
|
||||
NB_DISABLE_DNS="true" \
|
||||
NB_ENTRYPOINT_SERVICE_TIMEOUT="5" \
|
||||
NB_ENTRYPOINT_LOGIN_TIMEOUT="1"
|
||||
|
||||
ENTRYPOINT [ "/usr/local/bin/netbird", "up" ]
|
||||
ENTRYPOINT [ "/usr/local/bin/netbird-entrypoint.sh" ]
|
||||
|
||||
ARG NETBIRD_BINARY=netbird
|
||||
COPY client/netbird-entrypoint.sh /usr/local/bin/netbird-entrypoint.sh
|
||||
COPY "${NETBIRD_BINARY}" /usr/local/bin/netbird
|
||||
|
@ -20,7 +20,7 @@ var downCmd = &cobra.Command{
|
||||
|
||||
cmd.SetOut(cmd.OutOrStdout())
|
||||
|
||||
err := util.InitLog(logLevel, "console")
|
||||
err := util.InitLog(logLevel, util.LogConsole)
|
||||
if err != nil {
|
||||
log.Errorf("failed initializing log %v", err)
|
||||
return err
|
||||
|
@ -32,7 +32,7 @@ var loginCmd = &cobra.Command{
|
||||
|
||||
cmd.SetOut(cmd.OutOrStdout())
|
||||
|
||||
err := util.InitLog(logLevel, "console")
|
||||
err := util.InitLog(logLevel, util.LogConsole)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed initializing log %v", err)
|
||||
}
|
||||
@ -50,7 +50,7 @@ var loginCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
// workaround to run without service
|
||||
if logFile == "console" {
|
||||
if util.FindFirstLogPath(logFiles) == "" {
|
||||
err = handleRebrand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -21,7 +21,7 @@ func TestLogin(t *testing.T) {
|
||||
"--config",
|
||||
confPath,
|
||||
"--log-file",
|
||||
"console",
|
||||
util.LogConsole,
|
||||
"--setup-key",
|
||||
strings.ToUpper("a2c8e62b-38f5-4553-b31e-dd66c696cebb"),
|
||||
"--management-url",
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"os/signal"
|
||||
"path"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@ -51,7 +52,7 @@ var (
|
||||
defaultLogFile string
|
||||
oldDefaultLogFileDir string
|
||||
oldDefaultLogFile string
|
||||
logFile string
|
||||
logFiles []string
|
||||
daemonAddr string
|
||||
managementURL string
|
||||
adminURL string
|
||||
@ -120,7 +121,7 @@ func init() {
|
||||
rootCmd.PersistentFlags().StringVar(&adminURL, "admin-url", "", fmt.Sprintf("Admin Panel URL [http|https]://[host]:[port] (default \"%s\")", internal.DefaultAdminURL))
|
||||
rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", defaultConfigPath, "Netbird config file location")
|
||||
rootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "l", "info", "sets Netbird log level")
|
||||
rootCmd.PersistentFlags().StringVar(&logFile, "log-file", defaultLogFile, "sets Netbird log path. If console is specified the log will be output to stdout. If syslog is specified the log will be sent to syslog daemon.")
|
||||
rootCmd.PersistentFlags().StringSliceVar(&logFiles, "log-file", []string{defaultLogFile}, "sets Netbird log paths written to simultaneously. If `console` is specified the log will be output to stdout. If `syslog` is specified the log will be sent to syslog daemon. You can pass the flag multiple times or separate entries by `,` character")
|
||||
rootCmd.PersistentFlags().StringVarP(&setupKey, "setup-key", "k", "", "Setup key obtained from the Management Service Dashboard (used to register peer)")
|
||||
rootCmd.PersistentFlags().StringVar(&setupKeyPath, "setup-key-file", "", "The path to a setup key obtained from the Management Service Dashboard (used to register peer) This is ignored if the setup-key flag is provided.")
|
||||
rootCmd.MarkFlagsMutuallyExclusive("setup-key", "setup-key-file")
|
||||
@ -265,7 +266,7 @@ func getSetupKeyFromFile(setupKeyPath string) (string, error) {
|
||||
|
||||
func handleRebrand(cmd *cobra.Command) error {
|
||||
var err error
|
||||
if logFile == defaultLogFile {
|
||||
if slices.Contains(logFiles, defaultLogFile) {
|
||||
if migrateToNetbird(oldDefaultLogFile, defaultLogFile) {
|
||||
cmd.Printf("will copy Log dir %s and its content to %s\n", oldDefaultLogFileDir, defaultLogFileDir)
|
||||
err = cpDir(oldDefaultLogFileDir, defaultLogFileDir)
|
||||
|
@ -61,7 +61,7 @@ func (p *program) Start(svc service.Service) error {
|
||||
}
|
||||
}
|
||||
|
||||
serverInstance := server.New(p.ctx, configPath, logFile)
|
||||
serverInstance := server.New(p.ctx, configPath, util.FindFirstLogPath(logFiles))
|
||||
if err := serverInstance.Start(); err != nil {
|
||||
log.Fatalf("failed to start daemon: %v", err)
|
||||
}
|
||||
@ -112,7 +112,7 @@ func setupServiceControlCommand(cmd *cobra.Command, ctx context.Context, cancel
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := util.InitLog(logLevel, logFile); err != nil {
|
||||
if err := util.InitLog(logLevel, logFiles...); err != nil {
|
||||
return nil, fmt.Errorf("init log: %w", err)
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@ var runCmd = &cobra.Command{
|
||||
ctx, cancel := context.WithCancel(cmd.Context())
|
||||
|
||||
SetupCloseHandler(ctx, cancel)
|
||||
SetupDebugHandler(ctx, nil, nil, nil, logFile)
|
||||
SetupDebugHandler(ctx, nil, nil, nil, util.FindFirstLogPath(logFiles))
|
||||
|
||||
s, err := setupServiceControlCommand(cmd, ctx, cancel)
|
||||
if err != nil {
|
||||
|
@ -12,6 +12,8 @@ import (
|
||||
|
||||
"github.com/kardianos/service"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/netbirdio/netbird/util"
|
||||
)
|
||||
|
||||
var ErrGetServiceStatus = fmt.Errorf("failed to get service status")
|
||||
@ -41,7 +43,7 @@ func buildServiceArguments() []string {
|
||||
args = append(args, "--management-url", managementURL)
|
||||
}
|
||||
|
||||
if logFile != "" {
|
||||
for _, logFile := range logFiles {
|
||||
args = append(args, "--log-file", logFile)
|
||||
}
|
||||
|
||||
@ -54,7 +56,7 @@ func configurePlatformSpecificSettings(svcConfig *service.Config) error {
|
||||
// Respected only by systemd systems
|
||||
svcConfig.Dependencies = []string{"After=network.target syslog.target"}
|
||||
|
||||
if logFile != "console" {
|
||||
if logFile := util.FindFirstLogPath(logFiles); logFile != "" {
|
||||
setStdLogPath := true
|
||||
dir := filepath.Dir(logFile)
|
||||
|
||||
|
@ -46,7 +46,7 @@ var sshCmd = &cobra.Command{
|
||||
|
||||
cmd.SetOut(cmd.OutOrStdout())
|
||||
|
||||
err := util.InitLog(logLevel, "console")
|
||||
err := util.InitLog(logLevel, util.LogConsole)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed initializing log %v", err)
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ func statusFunc(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = util.InitLog(logLevel, "console")
|
||||
err = util.InitLog(logLevel, util.LogConsole)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed initializing log %v", err)
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ func upFunc(cmd *cobra.Command, args []string) error {
|
||||
|
||||
cmd.SetOut(cmd.OutOrStdout())
|
||||
|
||||
err := util.InitLog(logLevel, "console")
|
||||
err := util.InitLog(logLevel, util.LogConsole)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed initializing log %v", err)
|
||||
}
|
||||
@ -484,7 +484,7 @@ func parseCustomDNSAddress(modified bool) ([]byte, error) {
|
||||
if !isValidAddrPort(customDNSAddress) {
|
||||
return nil, fmt.Errorf("%s is invalid, it should be formatted as IP:Port string or as an empty string like \"\"", customDNSAddress)
|
||||
}
|
||||
if customDNSAddress == "" && logFile != "console" {
|
||||
if customDNSAddress == "" && util.FindFirstLogPath(logFiles) != "" {
|
||||
parsed = []byte("empty")
|
||||
} else {
|
||||
parsed = []byte(customDNSAddress)
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
_ = util.InitLog("trace", "console")
|
||||
_ = util.InitLog("trace", util.LogConsole)
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@ -28,6 +29,7 @@ import (
|
||||
"github.com/netbirdio/netbird/client/internal/peer"
|
||||
"github.com/netbirdio/netbird/client/internal/statemanager"
|
||||
mgmProto "github.com/netbirdio/netbird/management/proto"
|
||||
"github.com/netbirdio/netbird/util"
|
||||
)
|
||||
|
||||
const readmeContent = `Netbird debug bundle
|
||||
@ -283,7 +285,7 @@ func (g *BundleGenerator) createArchive() error {
|
||||
log.Errorf("Failed to add wg show output: %v", err)
|
||||
}
|
||||
|
||||
if g.logFile != "console" && g.logFile != "" {
|
||||
if g.logFile != "" && !slices.Contains(util.SpecialLogs, g.logFile) {
|
||||
if err := g.addLogfile(); err != nil {
|
||||
log.Errorf("Failed to add log file to debug bundle: %v", err)
|
||||
if err := g.trySystemdLogFallback(); err != nil {
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
_ = util.InitLog("debug", "console")
|
||||
_ = util.InitLog("debug", util.LogConsole)
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ func (m *MockWGIface) LastActivities() map[string]monotime.Time {
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
_ = util.InitLog("debug", "console")
|
||||
_ = util.InitLog("debug", util.LogConsole)
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ var connConf = ConnConfig{
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
_ = util.InitLog("trace", "console")
|
||||
_ = util.InitLog("trace", util.LogConsole)
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
105
client/netbird-entrypoint.sh
Executable file
105
client/netbird-entrypoint.sh
Executable file
@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eEuo pipefail
|
||||
|
||||
: ${NB_ENTRYPOINT_SERVICE_TIMEOUT:="5"}
|
||||
: ${NB_ENTRYPOINT_LOGIN_TIMEOUT:="1"}
|
||||
NETBIRD_BIN="${NETBIRD_BIN:-"netbird"}"
|
||||
export NB_LOG_FILE="${NB_LOG_FILE:-"console,/var/log/netbird/client.log"}"
|
||||
service_pids=()
|
||||
log_file_path=""
|
||||
|
||||
_log() {
|
||||
# mimic Go logger's output for easier parsing
|
||||
# 2025-04-15T21:32:00+08:00 INFO client/internal/config.go:495: setting notifications to disabled by default
|
||||
printf "$(date -Isec) ${1} ${BASH_SOURCE[1]}:${BASH_LINENO[1]}: ${2}\n" "${@:3}" >&2
|
||||
}
|
||||
|
||||
info() {
|
||||
_log INFO "$@"
|
||||
}
|
||||
|
||||
warn() {
|
||||
_log WARN "$@"
|
||||
}
|
||||
|
||||
on_exit() {
|
||||
info "Shutting down NetBird daemon..."
|
||||
if test "${#service_pids[@]}" -gt 0; then
|
||||
info "terminating service process IDs: ${service_pids[@]@Q}"
|
||||
kill -TERM "${service_pids[@]}" 2>/dev/null || true
|
||||
wait "${service_pids[@]}" 2>/dev/null || true
|
||||
else
|
||||
info "there are no service processes to terminate"
|
||||
fi
|
||||
}
|
||||
|
||||
wait_for_message() {
|
||||
local timeout="${1}" message="${2}"
|
||||
if test "${timeout}" -eq 0; then
|
||||
info "not waiting for log line ${message@Q} due to zero timeout."
|
||||
elif test -n "${log_file_path}"; then
|
||||
info "waiting for log line ${message@Q} for ${timeout} seconds..."
|
||||
grep -q "${message}" <(timeout "${timeout}" tail -F "${log_file_path}" 2>/dev/null)
|
||||
else
|
||||
info "log file unsupported, sleeping for ${timeout} seconds..."
|
||||
sleep "${timeout}"
|
||||
fi
|
||||
}
|
||||
|
||||
locate_log_file() {
|
||||
local log_files_string="${1}"
|
||||
|
||||
while read -r log_file; do
|
||||
case "${log_file}" in
|
||||
console | syslog) ;;
|
||||
*)
|
||||
log_file_path="${log_file}"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
done < <(sed 's#,#\n#g' <<<"${log_files_string}")
|
||||
|
||||
warn "log files parsing for ${log_files_string@Q} is not supported by debug bundles"
|
||||
warn "please consider removing the \$NB_LOG_FILE or setting it to real file, before gathering debug bundles."
|
||||
}
|
||||
|
||||
wait_for_daemon_startup() {
|
||||
local timeout="${1}"
|
||||
|
||||
if test -n "${log_file_path}"; then
|
||||
if ! wait_for_message "${timeout}" "started daemon server"; then
|
||||
warn "log line containing 'started daemon server' not found after ${timeout} seconds"
|
||||
warn "daemon failed to start, exiting..."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
warn "daemon service startup not discovered, sleeping ${timeout} instead"
|
||||
sleep "${timeout}"
|
||||
fi
|
||||
}
|
||||
|
||||
login_if_needed() {
|
||||
local timeout="${1}"
|
||||
|
||||
if test -n "${log_file_path}" && wait_for_message "${timeout}" 'peer has been successfully registered'; then
|
||||
info "already logged in, skipping 'netbird up'..."
|
||||
else
|
||||
info "logging in..."
|
||||
"${NETBIRD_BIN}" up
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
trap 'on_exit' SIGTERM SIGINT EXIT
|
||||
"${NETBIRD_BIN}" service run &
|
||||
service_pids+=("$!")
|
||||
info "registered new service process 'netbird service run', currently running: ${service_pids[@]@Q}"
|
||||
|
||||
locate_log_file "${NB_LOG_FILE}"
|
||||
wait_for_daemon_startup "${NB_ENTRYPOINT_SERVICE_TIMEOUT}"
|
||||
login_if_needed "${NB_ENTRYPOINT_LOGIN_TIMEOUT}"
|
||||
|
||||
wait "${service_pids[@]}"
|
||||
}
|
||||
|
||||
main "$@"
|
@ -32,6 +32,7 @@ import (
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
"github.com/netbirdio/netbird/signal/proto"
|
||||
signalServer "github.com/netbirdio/netbird/signal/server"
|
||||
"github.com/netbirdio/netbird/util"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -92,7 +93,7 @@ func TestConnectWithRetryRuns(t *testing.T) {
|
||||
func TestServer_Up(t *testing.T) {
|
||||
ctx := internal.CtxInitState(context.Background())
|
||||
|
||||
s := New(ctx, t.TempDir()+"/config.json", "console")
|
||||
s := New(ctx, t.TempDir()+"/config.json", util.LogConsole)
|
||||
|
||||
err := s.Start()
|
||||
require.NoError(t, err)
|
||||
@ -130,7 +131,7 @@ func (m *mockSubscribeEventsServer) Context() context.Context {
|
||||
func TestServer_SubcribeEvents(t *testing.T) {
|
||||
ctx := internal.CtxInitState(context.Background())
|
||||
|
||||
s := New(ctx, t.TempDir()+"/config.json", "console")
|
||||
s := New(ctx, t.TempDir()+"/config.json", util.LogConsole)
|
||||
|
||||
err := s.Start()
|
||||
require.NoError(t, err)
|
||||
|
@ -66,7 +66,7 @@ func main() {
|
||||
}
|
||||
logFile = file
|
||||
} else {
|
||||
_ = util.InitLog("trace", "console")
|
||||
_ = util.InitLog("trace", util.LogConsole)
|
||||
}
|
||||
|
||||
// Create the Fyne application.
|
||||
|
@ -41,7 +41,7 @@ import (
|
||||
const ValidKey = "A2C8E62B-38F5-4553-B31E-DD66C696CEBB"
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
_ = util.InitLog("debug", "console")
|
||||
_ = util.InitLog("debug", util.LogConsole)
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ var (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
_ = util.InitLog("debug", "console")
|
||||
_ = util.InitLog("debug", util.LogConsole)
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
_ = util.InitLog("trace", "console")
|
||||
_ = util.InitLog("trace", util.LogConsole)
|
||||
cobraConfig = &Config{}
|
||||
rootCmd.PersistentFlags().StringVarP(&cobraConfig.ListenAddress, "listen-address", "l", ":443", "listen address")
|
||||
rootCmd.PersistentFlags().StringVarP(&cobraConfig.ExposedAddress, "exposed-address", "e", "", "instance domain address (or ip) and port, it will be distributes between peers")
|
||||
|
@ -27,7 +27,7 @@ var (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
_ = util.InitLog("error", "console")
|
||||
_ = util.InitLog("error", util.LogConsole)
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ func TURNReaderMain() []testResult {
|
||||
func main() {
|
||||
var mode string
|
||||
|
||||
_ = util.InitLog("debug", "console")
|
||||
_ = util.InitLog("debug", util.LogConsole)
|
||||
flag.StringVar(&mode, "mode", "sender", "sender or receiver mode")
|
||||
flag.Parse()
|
||||
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := util.InitLog("info", "console")
|
||||
err := util.InitLog("info", util.LogConsole)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to initialize logger: %v", err)
|
||||
}
|
||||
|
77
util/log.go
77
util/log.go
@ -16,36 +16,54 @@ import (
|
||||
|
||||
const defaultLogSize = 15
|
||||
|
||||
const (
|
||||
LogConsole = "console"
|
||||
LogSyslog = "syslog"
|
||||
)
|
||||
|
||||
var (
|
||||
SpecialLogs = []string{
|
||||
LogSyslog,
|
||||
LogConsole,
|
||||
}
|
||||
)
|
||||
|
||||
// InitLog parses and sets log-level input
|
||||
func InitLog(logLevel string, logPath string) error {
|
||||
func InitLog(logLevel string, logs ...string) error {
|
||||
level, err := log.ParseLevel(logLevel)
|
||||
if err != nil {
|
||||
log.Errorf("Failed parsing log-level %s: %s", logLevel, err)
|
||||
return err
|
||||
}
|
||||
customOutputs := []string{"console", "syslog"}
|
||||
var writers []io.Writer
|
||||
logFmt := os.Getenv("NB_LOG_FORMAT")
|
||||
|
||||
if logPath != "" && !slices.Contains(customOutputs, logPath) {
|
||||
maxLogSize := getLogMaxSize()
|
||||
lumberjackLogger := &lumberjack.Logger{
|
||||
// Log file absolute path, os agnostic
|
||||
Filename: filepath.ToSlash(logPath),
|
||||
MaxSize: maxLogSize, // MB
|
||||
MaxBackups: 10,
|
||||
MaxAge: 30, // days
|
||||
Compress: true,
|
||||
for _, logPath := range logs {
|
||||
switch logPath {
|
||||
case LogSyslog:
|
||||
AddSyslogHook()
|
||||
logFmt = "syslog"
|
||||
case LogConsole:
|
||||
writers = append(writers, os.Stderr)
|
||||
case "":
|
||||
log.Warnf("empty log path received: %#v", logPath)
|
||||
default:
|
||||
writers = append(writers, newRotatedOutput(logPath))
|
||||
}
|
||||
log.SetOutput(io.Writer(lumberjackLogger))
|
||||
} else if logPath == "syslog" {
|
||||
AddSyslogHook()
|
||||
}
|
||||
|
||||
//nolint:gocritic
|
||||
if os.Getenv("NB_LOG_FORMAT") == "json" {
|
||||
if len(writers) > 1 {
|
||||
log.SetOutput(io.MultiWriter(writers...))
|
||||
} else if len(writers) == 1 {
|
||||
log.SetOutput(writers[0])
|
||||
}
|
||||
|
||||
switch logFmt {
|
||||
case "json":
|
||||
formatter.SetJSONFormatter(log.StandardLogger())
|
||||
} else if logPath == "syslog" {
|
||||
case "syslog":
|
||||
formatter.SetSyslogFormatter(log.StandardLogger())
|
||||
} else {
|
||||
default:
|
||||
formatter.SetTextFormatter(log.StandardLogger())
|
||||
}
|
||||
log.SetLevel(level)
|
||||
@ -55,6 +73,29 @@ func InitLog(logLevel string, logPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindFirstLogPath returns the first logs entry that could be a log path, that is neither empty, nor a special value
|
||||
func FindFirstLogPath(logs []string) string {
|
||||
for _, logFile := range logs {
|
||||
if logFile != "" && !slices.Contains(SpecialLogs, logFile) {
|
||||
return logFile
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func newRotatedOutput(logPath string) io.Writer {
|
||||
maxLogSize := getLogMaxSize()
|
||||
lumberjackLogger := &lumberjack.Logger{
|
||||
// Log file absolute path, os agnostic
|
||||
Filename: filepath.ToSlash(logPath),
|
||||
MaxSize: maxLogSize, // MB
|
||||
MaxBackups: 10,
|
||||
MaxAge: 30, // days
|
||||
Compress: true,
|
||||
}
|
||||
return lumberjackLogger
|
||||
}
|
||||
|
||||
func setGRPCLibLogger() {
|
||||
logOut := log.StandardLogger().Writer()
|
||||
if os.Getenv("GRPC_GO_LOG_SEVERITY_LEVEL") != "info" {
|
||||
|
Reference in New Issue
Block a user