TUN-3471: Add structured log context to logs

This commit is contained in:
Areg Harutyunyan 2020-12-28 18:10:01 +00:00 committed by Arég Harutyunyan
parent abab78730d
commit 55bf904689
40 changed files with 344 additions and 214 deletions

View File

@ -17,6 +17,8 @@ import (
"github.com/rs/zerolog"
)
const LogFieldOriginURL = "originURL"
type StartOptions struct {
OriginURL string
Headers http.Header

View File

@ -49,7 +49,7 @@ func NewWSConnection(log *zerolog.Logger, isSocks bool) Connection {
func (ws *Websocket) ServeStream(options *StartOptions, conn io.ReadWriter) error {
wsConn, err := createWebsocketStream(options, ws.log)
if err != nil {
ws.log.Error().Msgf("failed to connect to %s with error: %s", options.OriginURL, err)
ws.log.Err(err).Str(LogFieldOriginURL, options.OriginURL).Msg("failed to connect to origin")
return err
}
defer wsConn.Close()

View File

@ -15,6 +15,10 @@ import (
"github.com/urfave/cli/v2"
)
const (
LogFieldHost = "host"
)
// StartForwarder starts a client side websocket forward
func StartForwarder(forwarder config.Forwarder, shutdown <-chan struct{}, log *zerolog.Logger) error {
validURL, err := validation.ValidateUrl(forwarder.Listener)
@ -44,7 +48,7 @@ func StartForwarder(forwarder config.Forwarder, shutdown <-chan struct{}, log *z
// we could add a cmd line variable for this bool if we want the SOCK5 server to be on the client side
wsConn := carrier.NewWSConnection(log, false)
log.Info().Msgf("Start Websocket listener on: %s", validURL.Host)
log.Info().Str(LogFieldHost, validURL.Host).Msg("Start Websocket listener")
return carrier.StartForwarder(wsConn, validURL.Host, shutdown, options)
}
@ -88,14 +92,14 @@ func ssh(c *cli.Context) error {
if c.NArg() > 0 || c.IsSet(sshURLFlag) {
forwarder, err := config.ValidateUrl(c, true)
if err != nil {
log.Error().Msgf("Error validating origin URL: %s", err)
log.Err(err).Msg("Error validating origin URL")
return errors.Wrap(err, "error validating origin URL")
}
log.Info().Msgf("Start Websocket listener on: %s", forwarder.Host)
log.Info().Str(LogFieldHost, forwarder.Host).Msg("Start Websocket listener")
err = carrier.StartForwarder(wsConn, forwarder.Host, shutdownC, options)
if err != nil {
log.Error().Msgf("Error on Websocket listener: %s", err)
log.Err(err).Msg("Error on Websocket listener")
}
return err
}

View File

@ -212,11 +212,11 @@ func login(c *cli.Context) error {
rawURL := ensureURLScheme(args.First())
appURL, err := url.Parse(rawURL)
if args.Len() < 1 || err != nil {
log.Error().Msgf("Please provide the url of the Access application\n")
log.Error().Msg("Please provide the url of the Access application")
return err
}
if err := verifyTokenAtEdge(appURL, c, log); err != nil {
log.Error().Msgf("Could not verify token: %s", err)
log.Err(err).Msg("Could not verify token")
return err
}
@ -270,7 +270,7 @@ func curl(c *cli.Context) error {
}
tok, err = token.FetchToken(appURL, log)
if err != nil {
log.Error().Msgf("Failed to refresh token: %s", err)
log.Err(err).Msg("Failed to refresh token")
return err
}
}

View File

@ -7,8 +7,13 @@ import (
"github.com/rs/zerolog"
)
// ResolverServiceType is used to identify what kind of overwatch service this is
const ResolverServiceType = "resolver"
const (
// ResolverServiceType is used to identify what kind of overwatch service this is
ResolverServiceType = "resolver"
LogFieldResolverAddress = "resolverAddress"
LogFieldResolverPort = "resolverPort"
)
// ResolverService is used to wrap the tunneldns package's DNS over HTTP
// into a service model for the overwatch package.
@ -65,10 +70,16 @@ func (s *ResolverService) Run() error {
return err
}
<-readySignal
s.log.Info().Msgf("start resolver on: %s:%d", s.resolver.AddressOrDefault(), s.resolver.PortOrDefault())
resolverLog := s.log.With().
Str(LogFieldResolverAddress, s.resolver.AddressOrDefault()).
Uint16(LogFieldResolverPort, s.resolver.PortOrDefault()).
Logger()
resolverLog.Info().Msg("Starting resolver")
// wait for shutdown signal
<-s.shutdown
s.log.Info().Msgf("shutdown on: %s:%d", s.resolver.AddressOrDefault(), s.resolver.PortOrDefault())
resolverLog.Info().Msg("Shutting down resolver")
return l.Stop()
}

View File

@ -99,7 +99,7 @@ func readConfigFromPath(configPath string, log *zerolog.Logger) (Root, error) {
func (m *FileManager) WatcherItemDidChange(filepath string) {
config, err := m.GetConfig()
if err != nil {
m.log.Error().Msgf("Failed to read new config: %s", err)
m.log.Err(err).Msg("Failed to read new config")
return
}
m.log.Info().Msg("Config file has been updated")
@ -108,5 +108,5 @@ func (m *FileManager) WatcherItemDidChange(filepath string) {
// WatcherDidError notifies of errors with the file watcher
func (m *FileManager) WatcherDidError(err error) {
m.log.Error().Msgf("Config watcher encountered an error: %s", err)
m.log.Err(err).Msg("Config watcher encountered an error")
}

View File

@ -230,7 +230,7 @@ func installLinuxService(c *cli.Context) error {
userConfigFile := filepath.Base(c.String("config"))
userCredentialFile := config.DefaultCredentialFile
if err = copyUserConfiguration(userConfigDir, userConfigFile, userCredentialFile, log); err != nil {
log.Error().Msgf("Failed to copy user configuration: %s. Before running the service, ensure that %s contains two files, %s and %s", err,
log.Err(err).Msgf("Failed to copy user configuration. Before running the service, ensure that %s contains two files, %s and %s",
serviceConfigDir, serviceCredentialFile, serviceConfigFile)
return err
}
@ -283,30 +283,30 @@ func installSystemd(templateArgs *ServiceTemplateArgs, log *zerolog.Logger) erro
for _, serviceTemplate := range systemdTemplates {
err := serviceTemplate.Generate(templateArgs)
if err != nil {
log.Error().Msgf("error generating service template: %s", err)
log.Err(err).Msg("error generating service template")
return err
}
}
if err := runCommand("systemctl", "enable", "cloudflared.service"); err != nil {
log.Error().Msgf("systemctl enable cloudflared.service error: %s", err)
log.Err(err).Msg("systemctl enable cloudflared.service error")
return err
}
if err := runCommand("systemctl", "start", "cloudflared-update.timer"); err != nil {
log.Error().Msgf("systemctl start cloudflared-update.timer error: %s", err)
log.Err(err).Msg("systemctl start cloudflared-update.timer error")
return err
}
log.Info().Msgf("systemctl daemon-reload")
log.Info().Msg("systemctl daemon-reload")
return runCommand("systemctl", "daemon-reload")
}
func installSysv(templateArgs *ServiceTemplateArgs, log *zerolog.Logger) error {
confPath, err := sysvTemplate.ResolvePath()
if err != nil {
log.Error().Msgf("error resolving system path: %s", err)
log.Err(err).Msg("error resolving system path")
return err
}
if err := sysvTemplate.Generate(templateArgs); err != nil {
log.Error().Msgf("error generating system template: %s", err)
log.Err(err).Msg("error generating system template")
return err
}
for _, i := range [...]string{"2", "3", "4", "5"} {
@ -327,36 +327,36 @@ func uninstallLinuxService(c *cli.Context) error {
switch {
case isSystemd():
log.Info().Msgf("Using Systemd")
log.Info().Msg("Using Systemd")
return uninstallSystemd(log)
default:
log.Info().Msgf("Using SysV")
log.Info().Msg("Using SysV")
return uninstallSysv(log)
}
}
func uninstallSystemd(log *zerolog.Logger) error {
if err := runCommand("systemctl", "disable", "cloudflared.service"); err != nil {
log.Error().Msgf("systemctl disable cloudflared.service error: %s", err)
log.Err(err).Msg("systemctl disable cloudflared.service error")
return err
}
if err := runCommand("systemctl", "stop", "cloudflared-update.timer"); err != nil {
log.Error().Msgf("systemctl stop cloudflared-update.timer error: %s", err)
log.Err(err).Msg("systemctl stop cloudflared-update.timer error")
return err
}
for _, serviceTemplate := range systemdTemplates {
if err := serviceTemplate.Remove(); err != nil {
log.Error().Msgf("error removing service template: %s", err)
log.Err(err).Msg("error removing service template")
return err
}
}
log.Info().Msgf("Successfully uninstall cloudflared service")
log.Info().Msgf("Successfully uninstalled cloudflared service from systemd")
return nil
}
func uninstallSysv(log *zerolog.Logger) error {
if err := sysvTemplate.Remove(); err != nil {
log.Error().Msgf("error removing service template: %s", err)
log.Err(err).Msg("error removing service template")
return err
}
for _, i := range [...]string{"2", "3", "4", "5"} {
@ -369,6 +369,6 @@ func uninstallSysv(log *zerolog.Logger) error {
continue
}
}
log.Info().Msgf("Successfully uninstall cloudflared service")
log.Info().Msgf("Successfully uninstalled cloudflared service from sysv")
return nil
}

View File

@ -110,44 +110,44 @@ func installLaunchd(c *cli.Context) error {
log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog)
if isRootUser() {
log.Info().Msgf("Installing Argo Tunnel client as a system launch daemon. " +
log.Info().Msg("Installing Argo Tunnel client as a system launch daemon. " +
"Argo Tunnel client will run at boot")
} else {
log.Info().Msgf("Installing Argo Tunnel client as an user launch agent. " +
log.Info().Msg("Installing Argo Tunnel client as an user launch agent. " +
"Note that Argo Tunnel client will only run when the user is logged in. " +
"If you want to run Argo Tunnel client at boot, install with root permission. " +
"For more information, visit https://developers.cloudflare.com/argo-tunnel/reference/service/")
}
etPath, err := os.Executable()
if err != nil {
log.Error().Msgf("Error determining executable path: %s", err)
log.Err(err).Msg("Error determining executable path")
return fmt.Errorf("Error determining executable path: %v", err)
}
installPath, err := installPath()
if err != nil {
log.Error().Msgf("Error determining install path: %s", err)
log.Err(err).Msg("Error determining install path")
return errors.Wrap(err, "Error determining install path")
}
stdoutPath, err := stdoutPath()
if err != nil {
log.Error().Msgf("error determining stdout path: %s", err)
log.Err(err).Msg("error determining stdout path")
return errors.Wrap(err, "error determining stdout path")
}
stderrPath, err := stderrPath()
if err != nil {
log.Error().Msgf("error determining stderr path: %s", err)
log.Err(err).Msg("error determining stderr path")
return errors.Wrap(err, "error determining stderr path")
}
launchdTemplate := newLaunchdTemplate(installPath, stdoutPath, stderrPath)
templateArgs := ServiceTemplateArgs{Path: etPath}
err = launchdTemplate.Generate(&templateArgs)
if err != nil {
log.Error().Msgf("error generating launchd template: %s", err)
log.Err(err).Msg("error generating launchd template")
return err
}
plistPath, err := launchdTemplate.ResolvePath()
if err != nil {
log.Error().Msgf("error resolving launchd template path: %s", err)
log.Err(err).Msg("error resolving launchd template path")
return err
}
@ -159,9 +159,9 @@ func uninstallLaunchd(c *cli.Context) error {
log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog)
if isRootUser() {
log.Info().Msgf("Uninstalling Argo Tunnel as a system launch daemon")
log.Info().Msg("Uninstalling Argo Tunnel as a system launch daemon")
} else {
log.Info().Msgf("Uninstalling Argo Tunnel as an user launch agent")
log.Info().Msg("Uninstalling Argo Tunnel as an user launch agent")
}
installPath, err := installPath()
if err != nil {
@ -178,12 +178,12 @@ func uninstallLaunchd(c *cli.Context) error {
launchdTemplate := newLaunchdTemplate(installPath, stdoutPath, stderrPath)
plistPath, err := launchdTemplate.ResolvePath()
if err != nil {
log.Error().Msgf("error resolving launchd template path: %s", err)
log.Err(err).Msg("error resolving launchd template path")
return err
}
err = runCommand("launchctl", "unload", plistPath)
if err != nil {
log.Error().Msgf("error unloading: %s", err)
log.Err(err).Msg("error unloading")
return err
}

View File

@ -189,28 +189,28 @@ func handleServiceMode(c *cli.Context, shutdownC chan struct{}) error {
// start the main run loop that reads from the config file
f, err := watcher.NewFile()
if err != nil {
log.Error().Msgf("Cannot load config file: %s", err)
log.Err(err).Msg("Cannot load config file")
return err
}
configPath := config.FindOrCreateConfigPath()
configManager, err := config.NewFileManager(f, configPath, log)
if err != nil {
log.Error().Msgf("Cannot setup config file for monitoring: %s", err)
log.Err(err).Msg("Cannot setup config file for monitoring")
return err
}
log.Info().Msgf("monitoring config file at: %s", configPath)
serviceCallback := func(t string, name string, err error) {
if err != nil {
log.Error().Msgf("%s service: %s encountered an error: %s", t, name, err)
log.Err(err).Msgf("%s service: %s encountered an error", t, name)
}
}
serviceManager := overwatch.NewAppManager(serviceCallback)
appService := NewAppService(configManager, serviceManager, shutdownC, log)
if err := appService.Run(); err != nil {
log.Error().Msgf("Failed to start app service: %s", err)
log.Err(err).Msg("Failed to start app service")
return err
}
return nil

View File

@ -106,7 +106,7 @@ func transferRequest(requestURL string, log *zerolog.Logger) ([]byte, string, er
return nil, "", err
} else if len(buf) > 0 {
if err := putSuccess(client, requestURL); err != nil {
log.Error().Msgf("Failed to update resource success: %s", err)
log.Err(err).Msg("Failed to update resource success")
}
return buf, key, nil
}

View File

@ -78,6 +78,12 @@ const (
debugLevelWarning = "At debug level, request URL, method, protocol, content legnth and header will be logged. " +
"Response status, content length and header will also be logged in debug level."
LogFieldCommand = "command"
LogFieldExpandedPath = "expandedPath"
LogFieldPIDPathname = "pidPathname"
LogFieldTmpTraceFilename = "tmpTraceFilename"
LogFieldTraceOutputFilepath = "traceOutputFilepath"
)
var (
@ -173,14 +179,14 @@ func runAdhocNamedTunnel(sc *subcommandContext, name string) error {
return errors.Wrap(err, "failed to create tunnel")
}
} else {
sc.log.Info().Msgf("Tunnel already created with ID %s", tunnel.ID)
sc.log.Info().Str(LogFieldTunnelID, tunnel.ID.String()).Msg("Reusing existing tunnel with this name")
}
if r, ok := routeFromFlag(sc.c); ok {
if res, err := sc.route(tunnel.ID, r); err != nil {
sc.log.Error().Msgf("failed to create route, please create it manually. err: %v.", err)
sc.log.Err(err).Msg("failed to create route, please create it manually")
} else {
sc.log.Info().Msgf(res.SuccessSummary())
sc.log.Info().Msg(res.SuccessSummary())
}
}
@ -229,25 +235,31 @@ func StartServer(
if c.IsSet("trace-output") {
tmpTraceFile, err := ioutil.TempFile("", "trace")
if err != nil {
log.Error().Msgf("Failed to create new temporary file to save trace output: %s", err)
log.Err(err).Msg("Failed to create new temporary file to save trace output")
}
traceLog := log.With().Str(LogFieldTmpTraceFilename, tmpTraceFile.Name()).Logger()
defer func() {
if err := tmpTraceFile.Close(); err != nil {
log.Error().Msgf("Failed to close trace output file %s with error: %s", tmpTraceFile.Name(), err)
traceLog.Err(err).Msg("Failed to close temporary trace output file")
}
if err := os.Rename(tmpTraceFile.Name(), c.String("trace-output")); err != nil {
log.Error().Msgf("Failed to rename temporary trace output file %s to %s with error: %s", tmpTraceFile.Name(), c.String("trace-output"), err)
traceOutputFilepath := c.String("trace-output")
if err := os.Rename(tmpTraceFile.Name(), traceOutputFilepath); err != nil {
traceLog.
Err(err).
Str(LogFieldTraceOutputFilepath, traceOutputFilepath).
Msg("Failed to rename temporary trace output file")
} else {
err := os.Remove(tmpTraceFile.Name())
if err != nil {
log.Error().Msgf("Failed to remove the temporary trace file %s with error: %s", tmpTraceFile.Name(), err)
traceLog.Err(err).Msg("Failed to remove the temporary trace file")
}
}
}()
if err := trace.Start(tmpTraceFile); err != nil {
log.Error().Msgf("Failed to start trace: %s", err)
traceLog.Err(err).Msg("Failed to start trace")
return errors.Wrap(err, "Error starting tracing")
}
defer trace.Stop()
@ -277,7 +289,7 @@ func StartServer(
cloudflaredID, err := uuid.NewRandom()
if err != nil {
log.Error().Msgf("Cannot generate cloudflared ID: %s", err)
log.Err(err).Msg("Cannot generate cloudflared ID")
return err
}
@ -289,7 +301,8 @@ func StartServer(
// update needs to be after DNS proxy is up to resolve equinox server address
if updater.IsAutoupdateEnabled(c, log) {
log.Info().Msgf("Autoupdate frequency is set to %v", c.Duration("autoupdate-freq"))
autoupdateFreq := c.Duration("autoupdate-freq")
log.Info().Dur("autoupdateFreq", autoupdateFreq).Msg("Autoupdate frequency is set")
wg.Add(1)
go func() {
defer wg.Done()
@ -323,13 +336,13 @@ func StartServer(
}
tunnelConfig, ingressRules, err := prepareTunnelConfig(c, buildInfo, version, log, transportLog, namedTunnel, isUIEnabled, eventChannels)
if err != nil {
log.Error().Msgf("Couldn't start tunnel: %v", err)
log.Err(err).Msg("Couldn't start tunnel")
return err
}
metricsListener, err := listeners.Listen("tcp", c.String("metrics"))
if err != nil {
log.Error().Msgf("Error opening metrics server listener: %s", err)
log.Err(err).Msg("Error opening metrics server listener")
return errors.Wrap(err, "Error opening metrics server listener")
}
defer metricsListener.Close()
@ -404,7 +417,7 @@ func waitToShutdown(wg *sync.WaitGroup,
}
if err != nil {
log.Error().Msgf("Quitting due to error: %s", err)
log.Err(err).Msg("Quitting due to error")
} else {
log.Info().Msg("Quitting...")
}
@ -422,16 +435,16 @@ func notifySystemd(waitForSignal *signal.Signal) {
daemon.SdNotify(false, "READY=1")
}
func writePidFile(waitForSignal *signal.Signal, pidFile string, log *zerolog.Logger) {
func writePidFile(waitForSignal *signal.Signal, pidPathname string, log *zerolog.Logger) {
<-waitForSignal.Wait()
expandedPath, err := homedir.Expand(pidFile)
expandedPath, err := homedir.Expand(pidPathname)
if err != nil {
log.Error().Msgf("Unable to expand %s, try to use absolute path in --pidfile: %s", pidFile, err)
log.Err(err).Str(LogFieldPIDPathname, pidPathname).Msg("Unable to expand the path, try to use absolute path in --pidfile")
return
}
file, err := os.Create(expandedPath)
if err != nil {
log.Error().Msgf("Unable to write pid to %s: %s", expandedPath, err)
log.Err(err).Str(LogFieldExpandedPath, expandedPath).Msg("Unable to write pid")
return
}
defer file.Close()
@ -991,9 +1004,14 @@ func configureProxyDNSFlags(shouldHide bool) []cli.Flag {
Hidden: shouldHide,
}),
altsrc.NewStringSliceFlag(&cli.StringSliceFlag{
Name: "proxy-dns-bootstrap",
Usage: "bootstrap endpoint URL, you can specify multiple endpoints for redundancy.",
Value: cli.NewStringSlice("https://162.159.36.1/dns-query", "https://162.159.46.1/dns-query", "https://[2606:4700:4700::1111]/dns-query", "https://[2606:4700:4700::1001]/dns-query"),
Name: "proxy-dns-bootstrap",
Usage: "bootstrap endpoint URL, you can specify multiple endpoints for redundancy.",
Value: cli.NewStringSlice(
"https://162.159.36.1/dns-query",
"https://162.159.46.1/dns-query",
"https://[2606:4700:4700::1111]/dns-query",
"https://[2606:4700:4700::1001]/dns-query",
),
EnvVars: []string{"TUNNEL_DNS_BOOTSTRAP"},
Hidden: shouldHide,
}),
@ -1022,7 +1040,7 @@ func stdinControl(reconnectCh chan origin.ReconnectSignal, log *zerolog.Logger)
log.Info().Msgf("Sending reconnect signal %+v", reconnect)
reconnectCh <- reconnect
default:
log.Info().Msgf("Unknown command: %s", command)
log.Info().Str(LogFieldCommand, command).Msg("Unknown command")
fallthrough
case "help":
log.Info().Msg(`Supported command:

View File

@ -27,11 +27,15 @@ import (
"golang.org/x/crypto/ssh/terminal"
)
const LogFieldOriginCertPath = "originCertPath"
var (
developerPortal = "https://developers.cloudflare.com/argo-tunnel"
quickStartUrl = developerPortal + "/quickstart/quickstart/"
serviceUrl = developerPortal + "/reference/service/"
argumentsUrl = developerPortal + "/reference/arguments/"
LogFieldHostname = "hostname"
)
// returns the first path that contains a cert.pem file. If none of the DefaultConfigSearchDirectories
@ -92,29 +96,28 @@ func dnsProxyStandAlone(c *cli.Context) bool {
return c.IsSet("proxy-dns") && (!c.IsSet("hostname") && !c.IsSet("tag") && !c.IsSet("hello-world"))
}
func findOriginCert(c *cli.Context, log *zerolog.Logger) (string, error) {
originCertPath := c.String("origincert")
func findOriginCert(originCertPath string, log *zerolog.Logger) (string, error) {
if originCertPath == "" {
log.Info().Msgf("Cannot determine default origin certificate path. No file %s in %v", config.DefaultCredentialFile, config.DefaultConfigSearchDirectories())
if isRunningFromTerminal() {
log.Error().Msgf("You need to specify the origin certificate path with --origincert option, or set TUNNEL_ORIGIN_CERT environment variable. See %s for more information.", argumentsUrl)
return "", fmt.Errorf("Client didn't specify origincert path when running from terminal")
return "", fmt.Errorf("client didn't specify origincert path when running from terminal")
} else {
log.Error().Msgf("You need to specify the origin certificate path by specifying the origincert option in the configuration file, or set TUNNEL_ORIGIN_CERT environment variable. See %s for more information.", serviceUrl)
return "", fmt.Errorf("Client didn't specify origincert path")
return "", fmt.Errorf("client didn't specify origincert path")
}
}
var err error
originCertPath, err = homedir.Expand(originCertPath)
if err != nil {
log.Error().Msgf("Cannot resolve path %s: %s", originCertPath, err)
return "", fmt.Errorf("Cannot resolve path %s", originCertPath)
log.Err(err).Msgf("Cannot resolve origin certificate path")
return "", fmt.Errorf("cannot resolve path %s", originCertPath)
}
// Check that the user has acquired a certificate using the login command
ok, err := config.FileExists(originCertPath)
if err != nil {
log.Error().Msgf("Cannot check if origin cert exists at path %s", originCertPath)
return "", fmt.Errorf("Cannot check if origin cert exists at path %s", originCertPath)
return "", fmt.Errorf("cannot check if origin cert exists at path %s", originCertPath)
}
if !ok {
log.Error().Msgf(`Cannot find a valid certificate for your origin at the path:
@ -126,29 +129,26 @@ If you don't have a certificate signed by Cloudflare, run the command:
%s login
`, originCertPath, os.Args[0])
return "", fmt.Errorf("Cannot find a valid certificate at the path %s", originCertPath)
return "", fmt.Errorf("cannot find a valid certificate at the path %s", originCertPath)
}
return originCertPath, nil
}
func readOriginCert(originCertPath string, log *zerolog.Logger) ([]byte, error) {
log.Debug().Msgf("Reading origin cert from %s", originCertPath)
func readOriginCert(originCertPath string) ([]byte, error) {
// Easier to send the certificate as []byte via RPC than decoding it at this point
originCert, err := ioutil.ReadFile(originCertPath)
if err != nil {
log.Error().Msgf("Cannot read %s to load origin certificate: %s", originCertPath, err)
return nil, fmt.Errorf("Cannot read %s to load origin certificate", originCertPath)
return nil, fmt.Errorf("cannot read %s to load origin certificate", originCertPath)
}
return originCert, nil
}
func getOriginCert(c *cli.Context, log *zerolog.Logger) ([]byte, error) {
if originCertPath, err := findOriginCert(c, log); err != nil {
func getOriginCert(originCertPath string, log *zerolog.Logger) ([]byte, error) {
if originCertPath, err := findOriginCert(originCertPath, log); err != nil {
return nil, err
} else {
return readOriginCert(originCertPath, log)
return readOriginCert(originCertPath)
}
}
@ -164,9 +164,10 @@ func prepareTunnelConfig(
) (*origin.TunnelConfig, ingress.Ingress, error) {
isNamedTunnel := namedTunnel != nil
hostname, err := validation.ValidateHostname(c.String("hostname"))
configHostname := c.String("hostname")
hostname, err := validation.ValidateHostname(configHostname)
if err != nil {
log.Error().Msgf("Invalid hostname: %s", err)
log.Err(err).Str(LogFieldHostname, configHostname).Msg("Invalid hostname")
return nil, ingress.Ingress{}, errors.Wrap(err, "Invalid hostname")
}
isFreeTunnel := hostname == ""
@ -180,7 +181,7 @@ func prepareTunnelConfig(
tags, err := NewTagSliceFromCLI(c.StringSlice("tag"))
if err != nil {
log.Error().Msgf("Tag parse failure: %s", err)
log.Err(err).Msg("Tag parse failure")
return nil, ingress.Ingress{}, errors.Wrap(err, "Tag parse failure")
}
@ -188,7 +189,12 @@ func prepareTunnelConfig(
var originCert []byte
if !isFreeTunnel {
originCert, err = getOriginCert(c, log)
originCertPath := c.String("origincert")
originCertLog := log.With().
Str(LogFieldOriginCertPath, originCertPath).
Logger()
originCert, err = getOriginCert(originCertPath, &originCertLog)
if err != nil {
return nil, ingress.Ingress{}, errors.Wrap(err, "Error getting origin cert")
}

View File

@ -56,9 +56,13 @@ func newSearchByID(id uuid.UUID, c *cli.Context, log *zerolog.Logger, fs fileSys
}
func (s searchByID) Path() (string, error) {
originCertPath := s.c.String("origincert")
originCertLog := s.log.With().
Str(LogFieldOriginCertPath, originCertPath).
Logger()
// Fallback to look for tunnel credentials in the origin cert directory
if originCertPath, err := findOriginCert(s.c, s.log); err == nil {
if originCertPath, err := findOriginCert(originCertPath, &originCertLog); err == nil {
originCertDir := filepath.Dir(originCertPath)
if filePath, err := tunnelFilePath(s.id, originCertDir); err == nil {
if s.fs.validFilePath(filePath) {
@ -75,5 +79,5 @@ func (s searchByID) Path() (string, error) {
}
}
}
return "", fmt.Errorf("Tunnel credentials file not found")
return "", fmt.Errorf("tunnel credentials file not found")
}

View File

@ -9,6 +9,8 @@ import (
"github.com/rs/zerolog"
)
const LogFieldSignal = "signal"
// waitForSignal notifies all routines to shutdownC immediately by closing the
// shutdownC when one of the routines in main exits, or when this process receives
// SIGTERM/SIGINT
@ -19,11 +21,11 @@ func waitForSignal(errC chan error, shutdownC chan struct{}, log *zerolog.Logger
select {
case err := <-errC:
log.Info().Msgf("terminating due to error: %v", err)
log.Err(err).Msg("terminating due to error")
close(shutdownC)
return err
case s := <-signals:
log.Info().Msgf("terminating due to signal %s", s)
log.Info().Str(LogFieldSignal, s.String()).Msg("terminating due to signal")
close(shutdownC)
case <-shutdownC:
}

View File

@ -93,11 +93,16 @@ func (sc *subcommandContext) client() (tunnelstore.Client, error) {
func (sc *subcommandContext) credential() (*userCredential, error) {
if sc.userCredential == nil {
originCertPath, err := findOriginCert(sc.c, sc.log)
originCertPath := sc.c.String("origincert")
originCertLog := sc.log.With().
Str(LogFieldOriginCertPath, originCertPath).
Logger()
originCertPath, err := findOriginCert(originCertPath, &originCertLog)
if err != nil {
return nil, errors.Wrap(err, "Error locating origin cert")
}
blocks, err := readOriginCert(originCertPath, sc.log)
blocks, err := readOriginCert(originCertPath)
if err != nil {
return nil, errors.Wrapf(err, "Can't read origin cert from %s", originCertPath)
}

View File

@ -30,6 +30,8 @@ import (
const (
CredFileFlagAlias = "cred-file"
CredFileFlag = "credentials-file"
LogFieldTunnelID = "tunnelID"
)
var (
@ -360,7 +362,7 @@ func runNamedTunnel(sc *subcommandContext, tunnelRef string) error {
return errors.Wrap(err, "error parsing tunnel ID")
}
sc.log.Info().Msgf("Starting tunnel %s", tunnelID.String())
sc.log.Info().Str(LogFieldTunnelID, tunnelID.String()).Msg("Starting tunnel")
return sc.run(tunnelID)
}
@ -518,7 +520,7 @@ func routeCommand(c *cli.Context) error {
return err
}
sc.log.Info().Msg(res.SuccessSummary())
sc.log.Info().Str(LogFieldTunnelID, tunnelID.String()).Msg(res.SuccessSummary())
return nil
}

View File

@ -25,6 +25,8 @@ const (
isManagedInstallFile = ".installedFromPackageManager"
UpdateURL = "https://update.argotunnel.com"
StagingUpdateURL = "https://staging-update.argotunnel.com"
LogFieldVersion = "version"
)
var (
@ -141,7 +143,7 @@ func Update(c *cli.Context) error {
}
if updateOutcome.noUpdate() {
log.Info().Msgf("cloudflared is up to date (%s)", updateOutcome.Version)
log.Info().Str(LogFieldVersion, updateOutcome.Version).Msg("cloudflared is up to date")
return nil
}
@ -152,10 +154,10 @@ func Update(c *cli.Context) error {
func loggedUpdate(log *zerolog.Logger, options updateOptions) UpdateOutcome {
updateOutcome := checkForUpdateAndApply(options)
if updateOutcome.Updated {
log.Info().Msgf("cloudflared has been updated to version %s", updateOutcome.Version)
log.Info().Str(LogFieldVersion, updateOutcome.Version).Msg("cloudflared has been updated")
}
if updateOutcome.Error != nil {
log.Error().Msgf("update check failed: %s", updateOutcome.Error)
log.Err(updateOutcome.Error).Msg("update check failed: %s")
}
return updateOutcome
@ -203,7 +205,7 @@ func (a *AutoUpdater) Run(ctx context.Context) error {
a.log.Info().Msg("Restarting service managed by SysV...")
pid, err := a.listeners.StartProcess()
if err != nil {
a.log.Error().Msgf("Unable to restart server automatically: %s", err)
a.log.Err(err).Msg("Unable to restart server automatically")
return &statusErr{err: err}
}
// stop old process after autoupdate. Otherwise we create a new process

View File

@ -36,6 +36,8 @@ const (
// ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
// https://docs.microsoft.com/en-us/windows/desktop/debug/system-error-codes--1000-1299-
serviceControllerConnectionFailure = 1063
LogFieldWindowsServiceName = "windowsServiceName"
)
func runApp(app *cli.App, shutdownC, graceShutdownC chan struct{}) {
@ -70,7 +72,7 @@ func runApp(app *cli.App, shutdownC, graceShutdownC chan struct{}) {
isIntSess, err := svc.IsAnInteractiveSession()
if err != nil {
log.Fatal().Msgf("failed to determine if we are running in an interactive session: %v", err)
log.Fatal().Err(err).Msg("failed to determine if we are running in an interactive session")
}
if isIntSess {
app.Run(os.Args)
@ -88,7 +90,7 @@ func runApp(app *cli.App, shutdownC, graceShutdownC chan struct{}) {
app.Run(os.Args)
return
}
log.Fatal().Msgf("%s service failed: %v", windowsServiceName, err)
log.Fatal().Err(err).Msgf("%s service failed", windowsServiceName)
}
}
@ -103,7 +105,7 @@ func (s *windowsService) Execute(serviceArgs []string, r <-chan svc.ChangeReques
log := logger.Create(nil)
elog, err := eventlog.Open(windowsServiceName)
if err != nil {
log.Error().Msgf("Cannot open event log for %s with error: %s", windowsServiceName, err)
log.Err(err).Msgf("Cannot open event log for %s", windowsServiceName)
return
}
defer elog.Close()
@ -165,71 +167,74 @@ func (s *windowsService) Execute(serviceArgs []string, r <-chan svc.ChangeReques
func installWindowsService(c *cli.Context) error {
log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog)
log.Info().Msgf("Installing Argo Tunnel Windows service")
log.Info().Msg("Installing Argo Tunnel Windows service")
exepath, err := os.Executable()
if err != nil {
log.Error().Msgf("Cannot find path name that start the process")
log.Err(err).Msg("Cannot find path name that start the process")
return err
}
m, err := mgr.Connect()
if err != nil {
log.Error().Msgf("Cannot establish a connection to the service control manager: %s", err)
log.Err(err).Msg("Cannot establish a connection to the service control manager")
return err
}
defer m.Disconnect()
s, err := m.OpenService(windowsServiceName)
log = log.With().Str(LogFieldWindowsServiceName, windowsServiceName).Logger()
if err == nil {
s.Close()
log.Error().Msgf("service %s already exists", windowsServiceName)
log.Err(err).Msg("service already exists")
return fmt.Errorf("service %s already exists", windowsServiceName)
}
config := mgr.Config{StartType: mgr.StartAutomatic, DisplayName: windowsServiceDescription}
s, err = m.CreateService(windowsServiceName, exepath, config)
if err != nil {
log.Error().Msgf("Cannot install service %s", windowsServiceName)
log.Error().Msg("Cannot install service")
return err
}
defer s.Close()
log.Info().Msgf("Argo Tunnel agent service is installed")
log.Info().Msg("Argo Tunnel agent service is installed")
err = eventlog.InstallAsEventCreate(windowsServiceName, eventlog.Error|eventlog.Warning|eventlog.Info)
if err != nil {
s.Delete()
log.Error().Msgf("Cannot install event logger: %s", err)
log.Err(err).Msg("Cannot install event logger")
return fmt.Errorf("SetupEventLogSource() failed: %s", err)
}
err = configRecoveryOption(s.Handle)
if err != nil {
log.Error().Msgf("Cannot set service recovery actions: %s", err)
log.Err(err).Msg("Cannot set service recovery actions")
log.Info().Msgf("See %s to manually configure service recovery actions", windowsServiceUrl)
}
return nil
}
func uninstallWindowsService(c *cli.Context) error {
log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog)
log := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog).
With().
Str(LogFieldWindowsServiceName, windowsServiceName).Logger()
log.Info().Msgf("Uninstalling Argo Tunnel Windows Service")
log.Info().Msg("Uninstalling Argo Tunnel Windows Service")
m, err := mgr.Connect()
if err != nil {
log.Error().Msgf("Cannot establish a connection to the service control manager")
log.Error().Msg("Cannot establish a connection to the service control manager")
return err
}
defer m.Disconnect()
s, err := m.OpenService(windowsServiceName)
if err != nil {
log.Error().Msgf("service %s is not installed", windowsServiceName)
log.Error().Msg("service is not installed")
return fmt.Errorf("service %s is not installed", windowsServiceName)
}
defer s.Close()
err = s.Delete()
if err != nil {
log.Error().Msgf("Cannot delete service %s", windowsServiceName)
log.Error().Msg("Cannot delete service")
return err
}
log.Info().Msgf("Argo Tunnel agent service is uninstalled")
log.Info().Msg("Argo Tunnel agent service is uninstalled")
err = eventlog.Remove(windowsServiceName)
if err != nil {
log.Error().Msgf("Cannot remove event logger")
log.Error().Msg("Cannot remove event logger")
return fmt.Errorf("RemoveEventLogSource() failed: %s", err)
}
return nil

View File

@ -11,9 +11,7 @@ import (
"github.com/google/uuid"
)
const (
lbProbeUserAgentPrefix = "Mozilla/5.0 (compatible; Cloudflare-Traffic-Manager/1.0; +https://www.cloudflare.com/traffic-manager/;"
)
const LogFieldConnIndex = "connIndex"
type Config struct {
OriginClient OriginClient

View File

@ -63,13 +63,18 @@ func (e muxerShutdownError) Error() string {
}
func isHandshakeErrRecoverable(err error, connIndex uint8, observer *Observer) bool {
log := observer.log.With().
Uint8(LogFieldConnIndex, connIndex).
Err(err).
Logger()
switch err.(type) {
case edgediscovery.DialError:
observer.log.Error().Msgf("Connection %d unable to dial edge: %s", connIndex, err)
log.Error().Msg("Connection unable to dial edge")
case h2mux.MuxerHandshakeError:
observer.log.Error().Msgf("Connection %d handshake with edge server failed: %s", connIndex, err)
log.Error().Msg("Connection handshake with edge server failed")
default:
observer.log.Error().Msgf("Connection %d failed: %s", connIndex, err)
log.Error().Msg("Connection failed")
return false
}
return true

View File

@ -51,7 +51,7 @@ func (mc *MuxerConfig) H2MuxerConfig(h h2mux.MuxedStreamHandler, log *zerolog.Lo
}
// NewTunnelHandler returns a TunnelHandler, origin LAN IP and error
func NewH2muxConnection(ctx context.Context,
func NewH2muxConnection(
config *Config,
muxerConfig *MuxerConfig,
edgeConn net.Conn,
@ -123,7 +123,9 @@ func (h *h2muxConnection) ServeClassicTunnel(ctx context.Context, classicTunnel
return nil
}
// log errors and proceed to RegisterTunnel
h.observer.log.Error().Msgf("Couldn't reconnect connection %d. Reregistering it instead. Error was: %v", h.connIndex, err)
h.observer.log.Err(err).
Uint8(LogFieldConnIndex, h.connIndex).
Msg("Couldn't reconnect connection. Re-registering it instead.")
}
return h.registerTunnel(ctx, credentialManager, classicTunnel, registrationOptions)
})

View File

@ -26,7 +26,7 @@ var (
}
)
func newH2MuxConnection(ctx context.Context, t require.TestingT) (*h2muxConnection, *h2mux.Muxer) {
func newH2MuxConnection(t require.TestingT) (*h2muxConnection, *h2mux.Muxer) {
edgeConn, originConn := net.Pipe()
edgeMuxChan := make(chan *h2mux.Muxer)
go func() {
@ -38,7 +38,7 @@ func newH2MuxConnection(ctx context.Context, t require.TestingT) (*h2muxConnecti
edgeMuxChan <- edgeMux
}()
var connIndex = uint8(0)
h2muxConn, err, _ := NewH2muxConnection(ctx, testConfig, testMuxerConfig, originConn, connIndex, testObserver)
h2muxConn, err, _ := NewH2muxConnection(testConfig, testMuxerConfig, originConn, connIndex, testObserver)
require.NoError(t, err)
return h2muxConn, <-edgeMuxChan
}
@ -79,7 +79,7 @@ func TestServeStreamHTTP(t *testing.T) {
}
ctx, cancel := context.WithCancel(context.Background())
h2muxConn, edgeMux := newH2MuxConnection(ctx, t)
h2muxConn, edgeMux := newH2MuxConnection(t)
var wg sync.WaitGroup
wg.Add(2)
@ -120,7 +120,7 @@ func TestServeStreamHTTP(t *testing.T) {
func TestServeStreamWS(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
h2muxConn, edgeMux := newH2MuxConnection(ctx, t)
h2muxConn, edgeMux := newH2MuxConnection(t)
var wg sync.WaitGroup
wg.Add(2)
@ -179,7 +179,7 @@ func hasHeader(stream *h2mux.MuxedStream, name, val string) bool {
func benchmarkServeStreamHTTPSimple(b *testing.B, test testRequest) {
ctx, cancel := context.WithCancel(context.Background())
h2muxConn, edgeMux := newH2MuxConnection(ctx, b)
h2muxConn, edgeMux := newH2MuxConnection(b)
var wg sync.WaitGroup
wg.Add(2)

View File

@ -2,7 +2,6 @@ package connection
import (
"context"
"errors"
"io"
"math"
"net"
@ -23,10 +22,6 @@ const (
controlStreamUpgrade = "control-stream"
)
var (
errNotFlusher = errors.New("ResponseWriter doesn't implement http.Flusher")
)
type http2Connection struct {
conn net.Conn
server *http2.Server

View File

@ -380,7 +380,7 @@ func newTunnelMetrics() *tunnelMetrics {
serverLocations: serverLocations,
oldServerLocations: make(map[string]string),
muxerMetrics: newMuxerMetrics(),
tunnelsHA: NewTunnelsForHA(),
tunnelsHA: newTunnelsForHA(),
regSuccess: registerSuccess,
regFail: registerFail,
rpcFail: rpcFail,

View File

@ -10,6 +10,8 @@ import (
"github.com/rs/zerolog"
)
const LogFieldLocation = "location"
type Observer struct {
log *zerolog.Logger
metrics *tunnelMetrics
@ -28,7 +30,10 @@ func NewObserver(log *zerolog.Logger, tunnelEventChans []chan Event, uiEnabled b
func (o *Observer) logServerInfo(connIndex uint8, location, msg string) {
o.sendEvent(Event{Index: connIndex, EventType: Connected, Location: location})
o.log.Info().Msgf(msg)
o.log.Info().
Uint8(LogFieldConnIndex, connIndex).
Str(LogFieldLocation, location).
Msg(msg)
o.metrics.registerServerLocation(uint8ToString(connIndex), location)
}

View File

@ -118,7 +118,7 @@ func (s *autoProtocolSelector) Current() Protocol {
percentage, err := s.fetchFunc()
if err != nil {
s.log.Error().Msgf("Failed to refresh protocol, err: %v", err)
s.log.Err(err).Msg("Failed to refresh protocol")
return s.current
}

View File

@ -109,7 +109,7 @@ func (rsc *registrationServerClient) RegisterConnection(
observer.metrics.regSuccess.WithLabelValues("registerConnection").Inc()
observer.logServerInfo(connIndex, conn.Location, fmt.Sprintf("Connection %d registered with %s using ID %s", connIndex, conn.Location, conn.UUID))
observer.logServerInfo(connIndex, conn.Location, fmt.Sprintf("Connection %s registered", conn.UUID))
observer.sendConnectedEvent(connIndex, conn.Location)
return nil
@ -260,15 +260,15 @@ func (h *h2muxConnection) logServerInfo(ctx context.Context, rpcClient *tunnelSe
})
serverInfoMessage, err := serverInfoPromise.Result().Struct()
if err != nil {
h.observer.log.Error().Msgf("Failed to retrieve server information: %s", err)
h.observer.log.Err(err).Msg("Failed to retrieve server information")
return err
}
serverInfo, err := tunnelpogs.UnmarshalServerInfo(serverInfoMessage)
if err != nil {
h.observer.log.Error().Msgf("Failed to retrieve server information: %s", err)
h.observer.log.Err(err).Msg("Failed to retrieve server information")
return err
}
h.observer.logServerInfo(h.connIndex, serverInfo.LocationName, fmt.Sprintf("Connection %d connected to %s", h.connIndex, serverInfo.LocationName))
h.observer.logServerInfo(h.connIndex, serverInfo.LocationName, "Connection established")
return nil
}

View File

@ -15,7 +15,7 @@ type tunnelsForHA struct {
}
// NewTunnelsForHA initializes the Prometheus metrics etc for a tunnelsForHA.
func NewTunnelsForHA() tunnelsForHA {
func newTunnelsForHA() tunnelsForHA {
metrics := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "tunnel_ids",

View File

@ -18,6 +18,10 @@ import (
"github.com/rs/zerolog"
)
const (
LogFieldCFRay = "cfRay"
)
// Proxy is an HTTP server that proxies requests to a Client.
type Proxy struct {
client Client