Skip to content

Commit

Permalink
Refactored logging; Syslog support
Browse files Browse the repository at this point in the history
  • Loading branch information
DarthSim committed Jan 14, 2019
1 parent e0f925d commit ed79567
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 80 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Massive processing of remote images is a potentially dangerous thing, security-w
* [New Relic metrics](./docs/configuration.md#new-relic-metrics) * [New Relic metrics](./docs/configuration.md#new-relic-metrics)
* [Prometheus metrics](./docs/configuration.md#prometheus-metrics) * [Prometheus metrics](./docs/configuration.md#prometheus-metrics)
* [Error reporting](./docs/configuration.md#error-reporting) * [Error reporting](./docs/configuration.md#error-reporting)
* [Syslog](./docs/configuration.md#syslog)
* [Miscellaneous](./docs/configuration.md#miscellaneous) * [Miscellaneous](./docs/configuration.md#miscellaneous)
4. [Generating the URL](./docs/generating_the_url_basic.md) 4. [Generating the URL](./docs/generating_the_url_basic.md)
* [Basic](./docs/generating_the_url_basic.md) * [Basic](./docs/generating_the_url_basic.md)
Expand Down
3 changes: 1 addition & 2 deletions cmyk_profile.go
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import ( import (
"encoding/base64" "encoding/base64"
"io/ioutil" "io/ioutil"
"log"
"strings" "strings"
) )


Expand Down Expand Up @@ -20059,7 +20058,7 @@ func cmykProfilePath() (string, error) {
f.Close() f.Close()


_cmykProfilePath = f.Name() _cmykProfilePath = f.Name()
log.Printf("CMYK profile was written to %v", _cmykProfilePath) logNotice("CMYK profile was written to %v", _cmykProfilePath)
} }


return _cmykProfilePath, nil return _cmykProfilePath, nil
Expand Down
71 changes: 36 additions & 35 deletions config.go
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/hex" "encoding/hex"
"flag" "flag"
"fmt" "fmt"
"log"
"os" "os"
"runtime" "runtime"
"strconv" "strconv"
Expand Down Expand Up @@ -53,7 +52,7 @@ func hexEnvConfig(b *[]securityKey, name string) {


for i, part := range parts { for i, part := range parts {
if keys[i], err = hex.DecodeString(part); err != nil { if keys[i], err = hex.DecodeString(part); err != nil {
log.Fatalf("%s expected to be hex-encoded strings. Invalid: %s\n", name, part) logFatal("%s expected to be hex-encoded strings. Invalid: %s\n", name, part)
} }
} }


Expand All @@ -68,7 +67,7 @@ func hexFileConfig(b *[]securityKey, filepath string) {


f, err := os.Open(filepath) f, err := os.Open(filepath)
if err != nil { if err != nil {
log.Fatalf("Can't open file %s\n", filepath) logFatal("Can't open file %s\n", filepath)
} }


keys := []securityKey{} keys := []securityKey{}
Expand All @@ -84,12 +83,12 @@ func hexFileConfig(b *[]securityKey, filepath string) {
if key, err := hex.DecodeString(part); err == nil { if key, err := hex.DecodeString(part); err == nil {
keys = append(keys, key) keys = append(keys, key)
} else { } else {
log.Fatalf("%s expected to contain hex-encoded strings. Invalid: %s\n", filepath, part) logFatal("%s expected to contain hex-encoded strings. Invalid: %s\n", filepath, part)
} }
} }


if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
log.Fatalf("Failed to read file %s: %s", filepath, err) logFatal("Failed to read file %s: %s", filepath, err)
} }


*b = keys *b = keys
Expand All @@ -101,7 +100,7 @@ func presetEnvConfig(p presets, name string) {


for _, presetStr := range presetStrings { for _, presetStr := range presetStrings {
if err := parsePreset(p, presetStr); err != nil { if err := parsePreset(p, presetStr); err != nil {
log.Fatalln(err) logFatal(err.Error())
} }
} }
} }
Expand All @@ -114,18 +113,18 @@ func presetFileConfig(p presets, filepath string) {


f, err := os.Open(filepath) f, err := os.Open(filepath)
if err != nil { if err != nil {
log.Fatalf("Can't open file %s\n", filepath) logFatal("Can't open file %s\n", filepath)
} }


scanner := bufio.NewScanner(f) scanner := bufio.NewScanner(f)
for scanner.Scan() { for scanner.Scan() {
if err := parsePreset(p, scanner.Text()); err != nil { if err := parsePreset(p, scanner.Text()); err != nil {
log.Fatalln(err) logFatal(err.Error())
} }
} }


if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
log.Fatalf("Failed to read presets file: %s", err) logFatal("Failed to read presets file: %s", err)
} }
} }


Expand Down Expand Up @@ -221,6 +220,8 @@ var conf = config{
} }


func init() { func init() {
initSyslog()

keyPath := flag.String("keypath", "", "path of the file with hex-encoded key") keyPath := flag.String("keypath", "", "path of the file with hex-encoded key")
saltPath := flag.String("saltpath", "", "path of the file with hex-encoded salt") saltPath := flag.String("saltpath", "", "path of the file with hex-encoded salt")
presetsPath := flag.String("presets", "", "path of the file with presets") presetsPath := flag.String("presets", "", "path of the file with presets")
Expand Down Expand Up @@ -308,105 +309,105 @@ func init() {
strEnvConfig(&conf.SentryRelease, "IMGPROXY_SENTRY_RELEASE") strEnvConfig(&conf.SentryRelease, "IMGPROXY_SENTRY_RELEASE")


if len(conf.Keys) != len(conf.Salts) { if len(conf.Keys) != len(conf.Salts) {
log.Fatalf("Number of keys and number of salts should be equal. Keys: %d, salts: %d", len(conf.Keys), len(conf.Salts)) logFatal("Number of keys and number of salts should be equal. Keys: %d, salts: %d", len(conf.Keys), len(conf.Salts))
} }
if len(conf.Keys) == 0 { if len(conf.Keys) == 0 {
warning("No keys defined, so signature checking is disabled") logWarning("No keys defined, so signature checking is disabled")
conf.AllowInsecure = true conf.AllowInsecure = true
} }
if len(conf.Salts) == 0 { if len(conf.Salts) == 0 {
warning("No salts defined, so signature checking is disabled") logWarning("No salts defined, so signature checking is disabled")
conf.AllowInsecure = true conf.AllowInsecure = true
} }


if conf.SignatureSize < 1 || conf.SignatureSize > 32 { if conf.SignatureSize < 1 || conf.SignatureSize > 32 {
log.Fatalf("Signature size should be within 1 and 32, now - %d\n", conf.SignatureSize) logFatal("Signature size should be within 1 and 32, now - %d\n", conf.SignatureSize)
} }


if len(conf.Bind) == 0 { if len(conf.Bind) == 0 {
log.Fatalln("Bind address is not defined") logFatal("Bind address is not defined")
} }


if conf.ReadTimeout <= 0 { if conf.ReadTimeout <= 0 {
log.Fatalf("Read timeout should be greater than 0, now - %d\n", conf.ReadTimeout) logFatal("Read timeout should be greater than 0, now - %d\n", conf.ReadTimeout)
} }


if conf.WriteTimeout <= 0 { if conf.WriteTimeout <= 0 {
log.Fatalf("Write timeout should be greater than 0, now - %d\n", conf.WriteTimeout) logFatal("Write timeout should be greater than 0, now - %d\n", conf.WriteTimeout)
} }


if conf.DownloadTimeout <= 0 { if conf.DownloadTimeout <= 0 {
log.Fatalf("Download timeout should be greater than 0, now - %d\n", conf.DownloadTimeout) logFatal("Download timeout should be greater than 0, now - %d\n", conf.DownloadTimeout)
} }


if conf.Concurrency <= 0 { if conf.Concurrency <= 0 {
log.Fatalf("Concurrency should be greater than 0, now - %d\n", conf.Concurrency) logFatal("Concurrency should be greater than 0, now - %d\n", conf.Concurrency)
} }


if conf.MaxClients <= 0 { if conf.MaxClients <= 0 {
conf.MaxClients = conf.Concurrency * 10 conf.MaxClients = conf.Concurrency * 10
} }


if conf.TTL <= 0 { if conf.TTL <= 0 {
log.Fatalf("TTL should be greater than 0, now - %d\n", conf.TTL) logFatal("TTL should be greater than 0, now - %d\n", conf.TTL)
} }


if conf.MaxSrcDimension < 0 { if conf.MaxSrcDimension < 0 {
log.Fatalf("Max src dimension should be greater than or equal to 0, now - %d\n", conf.MaxSrcDimension) logFatal("Max src dimension should be greater than or equal to 0, now - %d\n", conf.MaxSrcDimension)
} else if conf.MaxSrcDimension > 0 { } else if conf.MaxSrcDimension > 0 {
warning("IMGPROXY_MAX_SRC_DIMENSION is deprecated and can be removed in future versions. Use IMGPROXY_MAX_SRC_RESOLUTION") logWarning("IMGPROXY_MAX_SRC_DIMENSION is deprecated and can be removed in future versions. Use IMGPROXY_MAX_SRC_RESOLUTION")
} }


if conf.MaxSrcResolution <= 0 { if conf.MaxSrcResolution <= 0 {
log.Fatalf("Max src resolution should be greater than 0, now - %d\n", conf.MaxSrcResolution) logFatal("Max src resolution should be greater than 0, now - %d\n", conf.MaxSrcResolution)
} }


if conf.MaxGifFrames <= 0 { if conf.MaxGifFrames <= 0 {
log.Fatalf("Max GIF frames should be greater than 0, now - %d\n", conf.MaxGifFrames) logFatal("Max GIF frames should be greater than 0, now - %d\n", conf.MaxGifFrames)
} }


if conf.Quality <= 0 { if conf.Quality <= 0 {
log.Fatalf("Quality should be greater than 0, now - %d\n", conf.Quality) logFatal("Quality should be greater than 0, now - %d\n", conf.Quality)
} else if conf.Quality > 100 { } else if conf.Quality > 100 {
log.Fatalf("Quality can't be greater than 100, now - %d\n", conf.Quality) logFatal("Quality can't be greater than 100, now - %d\n", conf.Quality)
} }


if conf.GZipCompression < 0 { if conf.GZipCompression < 0 {
log.Fatalf("GZip compression should be greater than or quual to 0, now - %d\n", conf.GZipCompression) logFatal("GZip compression should be greater than or quual to 0, now - %d\n", conf.GZipCompression)
} else if conf.GZipCompression > 9 { } else if conf.GZipCompression > 9 {
log.Fatalf("GZip compression can't be greater than 9, now - %d\n", conf.GZipCompression) logFatal("GZip compression can't be greater than 9, now - %d\n", conf.GZipCompression)
} }


if conf.IgnoreSslVerification { if conf.IgnoreSslVerification {
warning("Ignoring SSL verification is very unsafe") logWarning("Ignoring SSL verification is very unsafe")
} }


if conf.LocalFileSystemRoot != "" { if conf.LocalFileSystemRoot != "" {
stat, err := os.Stat(conf.LocalFileSystemRoot) stat, err := os.Stat(conf.LocalFileSystemRoot)
if err != nil { if err != nil {
log.Fatalf("Cannot use local directory: %s", err) logFatal("Cannot use local directory: %s", err)
} else { } else {
if !stat.IsDir() { if !stat.IsDir() {
log.Fatalf("Cannot use local directory: not a directory") logFatal("Cannot use local directory: not a directory")
} }
} }
if conf.LocalFileSystemRoot == "/" { if conf.LocalFileSystemRoot == "/" {
log.Print("Exposing root via IMGPROXY_LOCAL_FILESYSTEM_ROOT is unsafe") logNotice("Exposing root via IMGPROXY_LOCAL_FILESYSTEM_ROOT is unsafe")
} }
} }


if err := checkPresets(conf.Presets); err != nil { if err := checkPresets(conf.Presets); err != nil {
log.Fatalln(err) logFatal(err.Error())
} }


if conf.WatermarkOpacity <= 0 { if conf.WatermarkOpacity <= 0 {
log.Fatalln("Watermark opacity should be greater than 0") logFatal("Watermark opacity should be greater than 0")
} else if conf.WatermarkOpacity > 1 { } else if conf.WatermarkOpacity > 1 {
log.Fatalln("Watermark opacity should be less than or equal to 1") logFatal("Watermark opacity should be less than or equal to 1")
} }


if len(conf.PrometheusBind) > 0 && conf.PrometheusBind == conf.Bind { if len(conf.PrometheusBind) > 0 && conf.PrometheusBind == conf.Bind {
log.Fatalln("Can't use the same binding for the main server and Prometheus") logFatal("Can't use the same binding for the main server and Prometheus")
} }


initDownloading() initDownloading()
Expand Down
9 changes: 9 additions & 0 deletions docs/configuration.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -177,6 +177,15 @@ imgproxy can report occurred errors to Bugsnag, Honeybadger and Sentry:
* `IMGPROXY_SENTRY_ENVIRONMENT`: Sentry environment to report to. Default: `production`. * `IMGPROXY_SENTRY_ENVIRONMENT`: Sentry environment to report to. Default: `production`.
* `IMGPROXY_SENTRY_RELEASE`: Sentry release to report to. Default: `imgproxy/{imgproxy version}`. * `IMGPROXY_SENTRY_RELEASE`: Sentry release to report to. Default: `imgproxy/{imgproxy version}`.


### Syslog

imgproxy can send logs to syslog, but this feature is disabled by default. To enable it, set `IMGPROXY_SYSLOG_ENABLE` to `true`:

* `IMGPROXY_SYSLOG_ENABLE`: when `true`, enables sending logs to syslog;
* `IMGPROXY_SYSLOG_LEVEL`: maximum log level to send to syslog. Known levels are: `crit`, `error`, `warning` and `notice`. Default: `notice`;
* `IMGPROXY_SYSLOG_NETWORK`: network that will be used to connect to syslog. When blank, the local syslog server will be used. Known networks are `tcp`, `tcp4`, `tcp6`, `udp`, `udp4`, `udp6`, `ip`, `ip4`, `ip6`, `unix`, `unixgram` and `unixpacket`. Default: blank;
* `IMGPROXY_SYSLOG_ADDRESS`: address of the syslog service. Not used if `IMGPROXY_SYSLOG_NETWORK` is blank. Default: blank;

### Miscellaneous ### Miscellaneous


* `IMGPROXY_BASE_URL`: base URL prefix that will be added to every requested image URL. For example, if the base URL is `http://example.com/images` and `/path/to/image.png` is requested, imgproxy will download the source image from `http://example.com/images/path/to/image.png`. Default: blank. * `IMGPROXY_BASE_URL`: base URL prefix that will be added to every requested image URL. For example, if the base URL is `http://example.com/images` and `/path/to/image.png` is requested, imgproxy will download the source image from `http://example.com/images/path/to/image.png`. Default: blank.
5 changes: 0 additions & 5 deletions errors.go
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main


import ( import (
"fmt" "fmt"
"log"
"runtime" "runtime"
"strings" "strings"
) )
Expand Down Expand Up @@ -39,7 +38,3 @@ func stacktrace(skip int) string {


return strings.Join(lines, "\n") return strings.Join(lines, "\n")
} }

func warning(f string, args ...interface{}) {
log.Printf("\033[1;33m[WARNING]\033[0m %s", fmt.Sprintf(f, args...))
}
5 changes: 2 additions & 3 deletions examples/signature.go
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"log"
) )


func main() { func main() {
Expand All @@ -17,11 +16,11 @@ func main() {
var err error var err error


if keyBin, err = hex.DecodeString(key); err != nil { if keyBin, err = hex.DecodeString(key); err != nil {
log.Fatalln("Key expected to be hex-encoded string") logFatal("Key expected to be hex-encoded string")
} }


if saltBin, err = hex.DecodeString(salt); err != nil { if saltBin, err = hex.DecodeString(salt); err != nil {
log.Fatalf("Salt expected to be hex-encoded string") logFatal("Salt expected to be hex-encoded string")
} }


resize := "fill" resize := "fill"
Expand Down
3 changes: 1 addition & 2 deletions gcs_transport.go
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main


import ( import (
"context" "context"
"log"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
Expand All @@ -19,7 +18,7 @@ func newGCSTransport() http.RoundTripper {
client, err := storage.NewClient(context.Background(), option.WithCredentialsJSON([]byte(conf.GCSKey))) client, err := storage.NewClient(context.Background(), option.WithCredentialsJSON([]byte(conf.GCSKey)))


if err != nil { if err != nil {
log.Fatalf("Can't create GCS client: %s", err) logFatal("Can't create GCS client: %s", err)
} }


return gcsTransport{client} return gcsTransport{client}
Expand Down
90 changes: 90 additions & 0 deletions log.go
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,90 @@
package main

import (
"fmt"
"log"
"log/syslog"
"net/http"
)

const (
logRequestFmt = "[%s] %s: %s"
logRequestSyslogFmt = "REQUEST [%s] %s: %s"
logResponseFmt = "[%s] |\033[7;%dm %d \033[0m| %s"
logResponseSyslogFmt = "RESPONSE [%s] | %d | %s"
logWarningFmt = "\033[1;33m[WARNING]\033[0m %s"
logWarningSyslogFmt = "WARNING %s"
logFatalSyslogFmt = "FATAL %s"
)

func logRequest(reqID string, r *http.Request) {
path := r.URL.RequestURI()

log.Printf(logRequestFmt, reqID, r.Method, path)

if syslogWriter != nil {
syslogWriter.Notice(fmt.Sprintf(logRequestSyslogFmt, reqID, r.Method, path))
}
}

func logResponse(reqID string, status int, msg string) {
var color int

if status >= 500 {
color = 31
} else if status >= 400 {
color = 33
} else {
color = 32
}

log.Printf(logResponseFmt, reqID, color, status, msg)

if syslogWriter != nil {
msg := fmt.Sprintf(logResponseSyslogFmt, reqID, status, msg)

if status >= 500 {
if syslogLevel >= syslog.LOG_ERR {
syslogWriter.Err(msg)
}
} else if status >= 400 {
if syslogLevel >= syslog.LOG_WARNING {
syslogWriter.Warning(msg)
}
} else {
if syslogLevel >= syslog.LOG_NOTICE {
syslogWriter.Notice(msg)
}
}
}
}

func logNotice(f string, args ...interface{}) {
msg := fmt.Sprintf(f, args...)

log.Print(msg)

if syslogWriter != nil && syslogLevel >= syslog.LOG_NOTICE {
syslogWriter.Notice(msg)
}
}

func logWarning(f string, args ...interface{}) {
msg := fmt.Sprintf(f, args...)

log.Printf(logWarningFmt, msg)

if syslogWriter != nil && syslogLevel >= syslog.LOG_WARNING {
syslogWriter.Warning(fmt.Sprintf(logWarningSyslogFmt, msg))
}
}

func logFatal(f string, args ...interface{}) {
msg := fmt.Sprintf(f, args...)

if syslogWriter != nil {
syslogWriter.Crit(fmt.Sprintf(logFatalSyslogFmt, msg))
}

log.Fatal(msg)
}
Loading

0 comments on commit ed79567

Please sign in to comment.