• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cshum / imagor / 4142091150

10 Feb 2023 08:24AM UTC coverage: 90.999% (-0.2%) from 91.179%
4142091150

Pull #282

github

Adrian Shum
refactor interfaces
Pull Request #282: feat(server): Add optional Prometheus metrics server

67 of 67 new or added lines in 4 files covered. (100.0%)

5530 of 6077 relevant lines covered (91.0%)

1.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.58
/config/config.go
1
package config
2

3
import (
4
        "crypto/sha1"
5
        "crypto/sha256"
6
        "crypto/sha512"
7
        "flag"
8
        "fmt"
9
        "runtime"
10
        "strings"
11
        "time"
12

13
        "github.com/cshum/imagor/metrics/prometheusmetrics"
14

15
        "github.com/cshum/imagor"
16
        "github.com/cshum/imagor/imagorpath"
17
        "github.com/cshum/imagor/server"
18
        "github.com/peterbourgon/ff/v3"
19
        "go.uber.org/zap"
20
)
21

22
var baseConfig = []Option{
23
        withFileSystem,
24
        withHTTPLoader,
25
}
26

27
// NewImagor create imagor from config flags
28
func NewImagor(
29
        fs *flag.FlagSet, cb func() (*zap.Logger, bool), funcs ...Option,
30
) *imagor.Imagor {
1✔
31
        var (
1✔
32
                imagorSecret = fs.String("imagor-secret", "",
1✔
33
                        "Secret key for signing imagor URL")
1✔
34
                imagorUnsafe = fs.Bool("imagor-unsafe", false,
1✔
35
                        "Unsafe imagor that does not require URL signature. Prone to URL tampering")
1✔
36
                imagorAutoWebP = fs.Bool("imagor-auto-webp", false,
1✔
37
                        "Output WebP format automatically if browser supports")
1✔
38
                imagorAutoAVIF = fs.Bool("imagor-auto-avif", false,
1✔
39
                        "Output AVIF format automatically if browser supports (experimental)")
1✔
40
                imagorRequestTimeout = fs.Duration("imagor-request-timeout",
1✔
41
                        time.Second*30, "Timeout for performing imagor request")
1✔
42
                imagorLoadTimeout = fs.Duration("imagor-load-timeout",
1✔
43
                        0, "Timeout for imagor Loader request, should be smaller than imagor-request-timeout")
1✔
44
                imagorSaveTimeout = fs.Duration("imagor-save-timeout",
1✔
45
                        0, "Timeout for saving image to imagor Storage")
1✔
46
                imagorProcessTimeout = fs.Duration("imagor-process-timeout",
1✔
47
                        0, "Timeout for image processing")
1✔
48
                imagorBasePathRedirect = fs.String("imagor-base-path-redirect", "",
1✔
49
                        "URL to redirect for imagor / base path e.g. https://www.google.com")
1✔
50
                imagorBaseParams = fs.String("imagor-base-params", "",
1✔
51
                        "imagor endpoint base params that applies to all resulting images e.g. filters:watermark(example.jpg)")
1✔
52
                imagorProcessConcurrency = fs.Int64("imagor-process-concurrency",
1✔
53
                        -1, "Maximum number of image process to be executed simultaneously. Requests that exceed this limit are put in the queue. Set -1 for no limit")
1✔
54
                imagorProcessQueueSize = fs.Int64("imagor-process-queue-size",
1✔
55
                        -1, "Maximum number of image process that can be put in the queue. Requests that exceed this limit are rejected with HTTP status 429. Set -1 for no limit")
1✔
56
                imagorCacheHeaderTTL = fs.Duration("imagor-cache-header-ttl",
1✔
57
                        time.Hour*24*7, "imagor HTTP Cache-Control header TTL for successful image response")
1✔
58
                imagorCacheHeaderSWR = fs.Duration("imagor-cache-header-swr",
1✔
59
                        time.Hour*24, "imagor HTTP Cache-Control header stale-while-revalidate for successful image response")
1✔
60
                imagorCacheHeaderNoCache = fs.Bool("imagor-cache-header-no-cache",
1✔
61
                        false, "imagor HTTP Cache-Control header no-cache for successful image response")
1✔
62
                imagorModifiedTimeCheck = fs.Bool("imagor-modified-time-check", false,
1✔
63
                        "Check modified time of result image against the source image. This eliminates stale result but require more lookups")
1✔
64
                imagorDisableErrorBody       = fs.Bool("imagor-disable-error-body", false, "imagor disable response body on error")
1✔
65
                imagorDisableParamsEndpoint  = fs.Bool("imagor-disable-params-endpoint", false, "imagor disable /params endpoint")
1✔
66
                imagorSignerType             = fs.String("imagor-signer-type", "sha1", "imagor URL signature hasher type: sha1, sha256, sha512")
1✔
67
                imagorSignerTruncate         = fs.Int("imagor-signer-truncate", 0, "imagor URL signature truncate at length")
1✔
68
                imagorStoragePathStyle       = fs.String("imagor-storage-path-style", "original", "imagor storage path style: original, digest")
1✔
69
                imagorResultStoragePathStyle = fs.String("imagor-result-storage-path-style", "original", "imagor result storage path style: original, digest, suffix")
1✔
70

1✔
71
                options, logger, isDebug = applyOptions(fs, cb, append(funcs, baseConfig...)...)
1✔
72

1✔
73
                alg          = sha1.New
1✔
74
                hasher       imagorpath.StorageHasher
1✔
75
                resultHasher imagorpath.ResultStorageHasher
1✔
76
        )
1✔
77

1✔
78
        if strings.ToLower(*imagorSignerType) == "sha256" {
2✔
79
                alg = sha256.New
1✔
80
        } else if strings.ToLower(*imagorSignerType) == "sha512" {
3✔
81
                alg = sha512.New
1✔
82
        }
1✔
83

84
        if strings.ToLower(*imagorStoragePathStyle) == "digest" {
2✔
85
                hasher = imagorpath.DigestStorageHasher
1✔
86
        }
1✔
87

88
        if strings.ToLower(*imagorResultStoragePathStyle) == "digest" {
2✔
89
                resultHasher = imagorpath.DigestResultStorageHasher
1✔
90
        } else if strings.ToLower(*imagorResultStoragePathStyle) == "suffix" {
3✔
91
                resultHasher = imagorpath.SuffixResultStorageHasher
1✔
92
        }
3✔
93

1✔
94
        return imagor.New(append(
1✔
95
                options,
96
                imagor.WithSigner(imagorpath.NewHMACSigner(
1✔
97
                        alg, *imagorSignerTruncate, *imagorSecret,
1✔
98
                )),
1✔
99
                imagor.WithBasePathRedirect(*imagorBasePathRedirect),
1✔
100
                imagor.WithBaseParams(*imagorBaseParams),
1✔
101
                imagor.WithRequestTimeout(*imagorRequestTimeout),
1✔
102
                imagor.WithLoadTimeout(*imagorLoadTimeout),
1✔
103
                imagor.WithSaveTimeout(*imagorSaveTimeout),
1✔
104
                imagor.WithProcessTimeout(*imagorProcessTimeout),
1✔
105
                imagor.WithProcessConcurrency(*imagorProcessConcurrency),
1✔
106
                imagor.WithProcessQueueSize(*imagorProcessQueueSize),
1✔
107
                imagor.WithCacheHeaderTTL(*imagorCacheHeaderTTL),
1✔
108
                imagor.WithCacheHeaderSWR(*imagorCacheHeaderSWR),
1✔
109
                imagor.WithCacheHeaderNoCache(*imagorCacheHeaderNoCache),
1✔
110
                imagor.WithAutoWebP(*imagorAutoWebP),
1✔
111
                imagor.WithAutoAVIF(*imagorAutoAVIF),
1✔
112
                imagor.WithModifiedTimeCheck(*imagorModifiedTimeCheck),
1✔
113
                imagor.WithDisableErrorBody(*imagorDisableErrorBody),
1✔
114
                imagor.WithDisableParamsEndpoint(*imagorDisableParamsEndpoint),
1✔
115
                imagor.WithStoragePathStyle(hasher),
1✔
116
                imagor.WithResultStoragePathStyle(resultHasher),
1✔
117
                imagor.WithUnsafe(*imagorUnsafe),
1✔
118
                imagor.WithLogger(logger),
1✔
119
                imagor.WithDebug(isDebug),
1✔
120
        )...)
1✔
121
}
1✔
122

1✔
123
// CreateServer create server from config flags. Returns nil on version or help command
124
func CreateServer(args []string, funcs ...Option) (srv *server.Server) {
125
        var (
126
                fs     = flag.NewFlagSet("imagor", flag.ExitOnError)
1✔
127
                logger *zap.Logger
1✔
128
                err    error
1✔
129
                app    *imagor.Imagor
1✔
130

1✔
131
                debug        = fs.Bool("debug", false, "Debug mode")
1✔
132
                version      = fs.Bool("version", false, "imagor version")
1✔
133
                port         = fs.Int("port", 8000, "Server port")
1✔
134
                goMaxProcess = fs.Int("gomaxprocs", 0, "GOMAXPROCS")
1✔
135

1✔
136
                bind = fs.String("bind", "",
1✔
137
                        "Server address and port to bind .e.g. myhost:8888. This overrides server address and port config")
1✔
138

1✔
139
                _ = fs.String("config", ".env", "Retrieve configuration from the given file")
1✔
140

1✔
141
                serverAddress = fs.String("server-address", "",
1✔
142
                        "Server address")
1✔
143
                serverPathPrefix = fs.String("server-path-prefix", "",
1✔
144
                        "Server path prefix")
1✔
145
                serverCORS = fs.Bool("server-cors", false,
1✔
146
                        "Enable CORS")
1✔
147
                serverStripQueryString = fs.Bool("server-strip-query-string", false,
1✔
148
                        "Enable strip query string redirection")
1✔
149
                serverAccessLog = fs.Bool("server-access-log", false,
1✔
150
                        "Enable server access log")
1✔
151

1✔
152
                prometheusBind = fs.String("prometheus-bind", "", "Specify address and port to enable Prometheus metrics, e.g. :5000, prom:7000")
1✔
153
                prometheusPath = fs.String("prometheus-path", "", "Prometheus metrics path")
1✔
154
        )
1✔
155

1✔
156
        app = NewImagor(fs, func() (*zap.Logger, bool) {
1✔
157
                if err = ff.Parse(fs, args,
1✔
158
                        ff.WithEnvVars(),
2✔
159
                        ff.WithConfigFileFlag("config"),
1✔
160
                        ff.WithIgnoreUndefined(true),
1✔
161
                        ff.WithAllowMissingConfigFile(true),
1✔
162
                        ff.WithConfigFileParser(ff.EnvParser),
1✔
163
                ); err != nil {
1✔
164
                        panic(err)
1✔
165
                }
1✔
166
                if *debug {
×
167
                        logger = zap.Must(zap.NewDevelopment())
168
                } else {
2✔
169
                        logger = zap.Must(zap.NewProduction())
1✔
170
                }
2✔
171
                return logger, *debug
1✔
172
        }, funcs...)
1✔
173

1✔
174
        if *version {
175
                fmt.Println(imagor.Version)
176
                return
2✔
177
        }
1✔
178

1✔
179
        if *goMaxProcess > 0 {
1✔
180
                logger.Debug("GOMAXPROCS", zap.Int("count", *goMaxProcess))
181
                runtime.GOMAXPROCS(*goMaxProcess)
1✔
182
        }
×
183

×
184
        var pm *prometheusmetrics.PrometheusMetrics
×
185
        if *prometheusBind != "" {
186
                pm = prometheusmetrics.New(
1✔
187
                        prometheusmetrics.WithAddr(*prometheusBind),
2✔
188
                        prometheusmetrics.WithPath(*prometheusPath),
1✔
189
                        prometheusmetrics.WithLogger(logger),
1✔
190
                )
1✔
191
        }
1✔
192

1✔
193
        return server.New(app,
1✔
194
                server.WithAddr(*bind),
195
                server.WithPort(*port),
1✔
196
                server.WithAddress(*serverAddress),
1✔
197
                server.WithPathPrefix(*serverPathPrefix),
1✔
198
                server.WithCORS(*serverCORS),
1✔
199
                server.WithStripQueryString(*serverStripQueryString),
1✔
200
                server.WithAccessLog(*serverAccessLog),
1✔
201
                server.WithLogger(logger),
1✔
202
                server.WithDebug(*debug),
1✔
203
                server.WithMetrics(pm),
1✔
204
        )
1✔
205
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc