Skip to content

Commit 71a4222

Browse files
committed
continue the munging around, TODO figure out how to configure the env vars
1 parent 315eb65 commit 71a4222

File tree

8 files changed

+37
-97
lines changed

8 files changed

+37
-97
lines changed

api/agent/agent.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,23 +1177,24 @@ func newHotContainer(ctx context.Context, evictor Evictor, call *call, cfg *Conf
11771177
// have to be read or *BOTH* blocked consistently. In other words, we cannot block one and continue
11781178
// reading from the other one without risking head-of-line blocking.
11791179

1180-
// TODO(reed): we should let the syslog driver pick this up really but our
1181-
// default story sucks there
1182-
11831180
// disable container logs if they're disabled on the call (pure_runner) -
11841181
// users may use syslog to get container logs, unrelated to this writer.
11851182
// otherwise, make a line writer and allow logrus DEBUG logs to host stderr
11861183
// between function invocations from the container.
11871184

11881185
var bufs []*bytes.Buffer
11891186
var stderr io.WriteCloser = call.stderr
1190-
if _, ok := stderr.(common.NoopReadWriteCloser); !ok {
1187+
if _, ok := stderr.(common.NoopReadWriteCloser); !ok && !cfg.DisableDebugUserLogs {
11911188
gw := common.NewGhostWriter()
11921189
buf1 := bufPool.Get().(*bytes.Buffer)
1193-
// TODO(reed): this logger may have garbage in it between calls, easy fix
1194-
// is to make a new one each swap, it's cheap enough to be doable.
1190+
// TODO(reed): this logger may have garbage in it between calls (without
1191+
// calling Close() to flush newlines, since we're swapping we can't), easy
1192+
// fix is to make a new one each swap, it's cheap enough to be doable.
1193+
// TODO(reed): we should only do this if they configure to log stderr, not if they use WithLogger(),
1194+
// for now use explicit disable with DisableDebugUserLogs
11951195
sec := &nopCloser{newLogWriter(
11961196
logrus.WithFields(logrus.Fields{"tag": "stderr", "app_id": call.AppID, "fn_id": call.FnID, "image": call.Image, "container_id": id}),
1197+
cfg.UserLogLevel,
11971198
)}
11981199
gw.Swap(newLineWriterWithBuffer(buf1, sec))
11991200
stderr = gw
@@ -1316,7 +1317,6 @@ func (c *container) DisableNet() bool { return c.disableNet }
13161317
func (c *container) WriteStat(ctx context.Context, stat driver_stats.Stat) {
13171318
for key, value := range stat.Metrics {
13181319
if m, ok := dockerMeasures[key]; ok {
1319-
common.Logger(ctx).WithField(key, value).Info("container stats")
13201320
stats.Record(ctx, m.M(int64(value)))
13211321
}
13221322
}

api/agent/agent_test.go

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -275,65 +275,6 @@ func TestGetCallFromModelRoundTripACall(t *testing.T) {
275275
}
276276
}
277277

278-
func TestLoggerIsStringerAndWorks(t *testing.T) {
279-
// TODO test limit writer, logrus writer, etc etc
280-
281-
var call models.Call
282-
logger := setupLogger(context.Background(), 1*1024*1024, true, &call)
283-
284-
if _, ok := logger.(fmt.Stringer); !ok {
285-
// NOTE: if you are reading, maybe what you've done is ok, but be aware we were relying on this for optimization...
286-
t.Fatal("you turned the logger into something inefficient and possibly better all at the same time, how dare ye!")
287-
}
288-
289-
str := "0 line\n1 line\n2 line\n\n4 line"
290-
logger.Write([]byte(str))
291-
292-
strGot := logger.(fmt.Stringer).String()
293-
294-
if strGot != str {
295-
t.Fatal("logs did not match expectations, like being an adult", strGot, str)
296-
}
297-
298-
logger.Close() // idk maybe this would panic might as well ca this
299-
300-
// TODO we could check for the toilet to flush here to logrus
301-
}
302-
303-
func TestLoggerTooBig(t *testing.T) {
304-
305-
var call models.Call
306-
logger := setupLogger(context.Background(), 10, true, &call)
307-
308-
str := fmt.Sprintf("0 line\n1 l\n-----max log size 10 bytes exceeded, truncating log-----\n")
309-
310-
n, err := logger.Write([]byte(str))
311-
if err != nil {
312-
t.Fatalf("err returned, but should not fail err=%v n=%d", err, n)
313-
}
314-
if n != len(str) {
315-
t.Fatalf("n should be %d, but got=%d", len(str), n)
316-
}
317-
318-
// oneeeeee moreeee time... (cue in Daft Punk), the results appear as if we wrote
319-
// again... But only "limit" bytes should succeed, ignoring the subsequent writes...
320-
n, err = logger.Write([]byte(str))
321-
if err != nil {
322-
t.Fatalf("err returned, but should not fail err=%v n=%d", err, n)
323-
}
324-
if n != len(str) {
325-
t.Fatalf("n should be %d, but got=%d", len(str), n)
326-
}
327-
328-
strGot := logger.(fmt.Stringer).String()
329-
330-
if strGot != str {
331-
t.Fatalf("logs did not match expectations, like being an adult got=\n%v\nexpected=\n%v\n", strGot, str)
332-
}
333-
334-
logger.Close()
335-
}
336-
337278
type testListener struct {
338279
afterCall func(context.Context, *models.Call) error
339280
}

api/agent/call.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,17 @@ func WithDockerAuth(auth docker.Auther) CallOpt {
213213
}
214214
}
215215

216-
func (a *agent) WithStderrLogger() CallOpt {
216+
// WithStderrLogger configures a call to have its container logs logged by fn.
217+
// Configure UserLogLevel or DisableDebugUserLogs on agent to change behavior.
218+
func WithStderrLogger() CallOpt {
219+
// TODO(reed): we could take a context here which would allow request level logging vars on ctx to be used here too
217220
return func(c *call) error {
218-
// XXX(reed): allow configuring the level / turning off
219-
c.stderr = setupLogger(c.Call)
221+
// TODO(reed): fucking hell this is a pain to configure
222+
if a.cfg.DisableDebugUserLogs {
223+
return nil
224+
}
225+
226+
c.stderr = setupLogger(a.cfg.UserLogLevel, c.Call)
220227
return nil
221228
}
222229
}
@@ -328,10 +335,6 @@ func (c *call) ResponseWriter() http.ResponseWriter {
328335
return c.respWriter.(http.ResponseWriter)
329336
}
330337

331-
func (c *call) StdErr() io.ReadWriteCloser {
332-
return c.stderr
333-
}
334-
335338
func (c *call) AddUserExecutionTime(dur time.Duration) {
336339
if c.userExecTime == nil {
337340
c.userExecTime = new(time.Duration)

api/agent/config.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type Config struct {
3838
MaxTmpFsInodes uint64 `json:"max_tmpfs_inodes"`
3939
DisableReadOnlyRootFs bool `json:"disable_readonly_rootfs"`
4040
DisableDebugUserLogs bool `json:"disable_debug_user_logs"`
41+
UserLogLevel string `json:"user_log_level"`
4142
IOFSEnableTmpfs bool `json:"iofs_enable_tmpfs"`
4243
IOFSAgentPath string `json:"iofs_path"`
4344
IOFSMountRoot string `json:"iofs_mount_root"`
@@ -69,16 +70,14 @@ const (
6970
EnvHotPoll = "FN_HOT_POLL_MSECS"
7071
// EnvHotLauncherTimeout is the timeout for a hot container queue to persist if idle
7172
EnvHotLauncherTimeout = "FN_HOT_LAUNCHER_TIMEOUT_MSECS"
72-
// EnvHotStartTimeout is the timeout for a hot container to be created including docker-pull
73+
// EnvHotPullTimeout is the timeout for a hot container to be created including docker-pull
7374
EnvHotPullTimeout = "FN_HOT_PULL_TIMEOUT_MSECS"
7475
// EnvHotStartTimeout is the timeout for a hot container to become available for use for requests after EnvHotStartTimeout
7576
EnvHotStartTimeout = "FN_HOT_START_TIMEOUT_MSECS"
7677
// EnvMaxResponseSize is the maximum number of bytes that a function may return from an invocation
7778
EnvMaxResponseSize = "FN_MAX_RESPONSE_SIZE"
78-
// EnvHdrMaxResponseSize is the maximum number of bytes that a function may return in an invocation header
79+
// EnvMaxHdrResponseSize is the maximum number of bytes that a function may return in an invocation header
7980
EnvMaxHdrResponseSize = "FN_MAX_HDR_RESPONSE_SIZE"
80-
// EnvMaxLogSize is the maximum size that a function's log may reach
81-
EnvMaxLogSize = "FN_MAX_LOG_SIZE_BYTES"
8281
// EnvMaxTotalCPU is the maximum CPU that will be reserved across all containers
8382
EnvMaxTotalCPU = "FN_MAX_TOTAL_CPU_MCPUS"
8483
// EnvMaxTotalMemory is the maximum memory that will be reserved across all containers
@@ -106,6 +105,8 @@ const (
106105
EnvDisableReadOnlyRootFs = "FN_DISABLE_READONLY_ROOTFS"
107106
// EnvDisableDebugUserLogs disables user function logs being logged at level debug. wise to enable for production.
108107
EnvDisableDebugUserLogs = "FN_DISABLE_DEBUG_USER_LOGS"
108+
// EnvUserLogLevel is the logging level to use for user's function logs to be logged by fn. to disable explicitly, use FN_DISABLE_DEBUG_USER_LOGS
109+
EnvUserLogLevel = "FN_USER_LOG_LEVEL"
109110

110111
// EnvIOFSEnableTmpfs enables creating a per-container tmpfs mount for the IOFS
111112
EnvIOFSEnableTmpfs = "FN_IOFS_TMPFS"
@@ -140,7 +141,6 @@ const (
140141
func NewConfig() (*Config, error) {
141142
cfg := &Config{
142143
MinDockerVersion: "17.10.0-ce",
143-
MaxLogSize: 1 * 1024 * 1024,
144144
PreForkImage: "busybox",
145145
PreForkCmd: "tail -f /dev/null",
146146
}
@@ -154,7 +154,6 @@ func NewConfig() (*Config, error) {
154154
err = setEnvMsecs(err, EnvDetachedHeadroom, &cfg.DetachedHeadRoom, time.Duration(360)*time.Second)
155155
err = setEnvUint(err, EnvMaxResponseSize, &cfg.MaxResponseSize)
156156
err = setEnvUint(err, EnvMaxHdrResponseSize, &cfg.MaxHdrResponseSize)
157-
err = setEnvUint(err, EnvMaxLogSize, &cfg.MaxLogSize)
158157
err = setEnvUint(err, EnvMaxTotalCPU, &cfg.MaxTotalCPU)
159158
err = setEnvUint(err, EnvMaxTotalMemory, &cfg.MaxTotalMemory)
160159
err = setEnvUint(err, EnvMaxFsSize, &cfg.MaxFsSize)
@@ -176,6 +175,7 @@ func NewConfig() (*Config, error) {
176175
err = setEnvBool(err, EnvEnableNBResourceTracker, &cfg.EnableNBResourceTracker)
177176
err = setEnvBool(err, EnvDisableReadOnlyRootFs, &cfg.DisableReadOnlyRootFs)
178177
err = setEnvBool(err, EnvDisableDebugUserLogs, &cfg.DisableDebugUserLogs)
178+
err = setEnvStr(err, EnvUserLogLevel, &cfg.UserLogLevel)
179179
err = setEnvUint(err, EnvImageCleanMaxSize, &cfg.ImageCleanMaxSize)
180180
err = setEnvStr(err, EnvImageCleanExemptTags, &cfg.ImageCleanExemptTags)
181181
err = setEnvBool(err, EnvImageEnableVolume, &cfg.ImageEnableVolume)
@@ -184,11 +184,6 @@ func NewConfig() (*Config, error) {
184184
return cfg, err
185185
}
186186

187-
if cfg.MaxLogSize > math.MaxInt64 {
188-
// for safety during uint64 to int conversions in Write()/Read(), etc.
189-
return cfg, fmt.Errorf("error invalid %s %v > %v", EnvMaxLogSize, cfg.MaxLogSize, math.MaxInt64)
190-
}
191-
192187
return cfg, nil
193188
}
194189

api/agent/func_logger.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ var (
1515
)
1616

1717
// * [always] writes bytes per line to stderr as DEBUG
18-
func setupLogger(c *models.Call) io.WriteCloser {
18+
func setupLogger(level string, c *models.Call) io.WriteCloser {
1919
lbuf := bufPool.Get().(*bytes.Buffer)
2020

2121
close := func() {
@@ -25,7 +25,7 @@ func setupLogger(c *models.Call) io.WriteCloser {
2525
}
2626

2727
stderrLogger := logrus.WithFields(logrus.Fields{"user_log": true, "app_id": c.AppID, "fn_id": c.FnID, "image": c.Image, "call_id": c.ID})
28-
loggo := newLogWriter(stderrLogger)
28+
loggo := newLogWriter(stderrLogger, level)
2929
linew := newLineWriterWithBuffer(lbuf, loggo)
3030
linew = &fCloser{
3131
close: func() error {
@@ -54,21 +54,27 @@ func (n *nopCloser) Close() error { return nil }
5454
// logWriter will log (to real stderr) every call to Write as a line. it should
5555
// be wrapped with a lineWriter so that the output makes sense.
5656
type logWriter struct {
57-
// level string // XXX(reed):
58-
logrus.FieldLogger
57+
level logrus.Level
58+
logger logrus.FieldLogger
5959
closed uint32
6060
}
6161

62-
func newLogWriter(logger logrus.FieldLogger) io.WriteCloser {
63-
return &logWriter{FieldLogger: logger}
62+
func newLogWriter(logger logrus.FieldLogger, level string) io.WriteCloser {
63+
lv, err := logrus.ParseLevel(level)
64+
if err != nil {
65+
// TODO(reed): we should do this at the config level instead? it's an optional option to begin with tho (StderrLogger)
66+
lv = logrus.InfoLevel // default
67+
}
68+
69+
return &logWriter{logger: logger, level: lv}
6470
}
6571

6672
func (l *logWriter) Write(b []byte) (int, error) {
6773
if atomic.LoadUint32(&l.closed) == 1 {
6874
// we don't want to return 0/error or the container will get shut down
6975
return len(b), nil
7076
}
71-
l.Debug(string(b))
77+
l.logger.WithFields(nil).Log(l.level, string(b))
7278
return len(b), nil
7379
}
7480

api/agent/lb_agent_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,6 @@ func (c *mockRunnerCall) ResponseWriter() http.ResponseWriter {
125125
return c.rw
126126
}
127127

128-
func (c *mockRunnerCall) StdErr() io.ReadWriteCloser {
129-
return c.stdErr
130-
}
131-
132128
func (c *mockRunnerCall) Model() *models.Call {
133129
return c.model
134130
}

api/runnerpool/runner_pool.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ type RunnerCall interface {
5959
Extensions() map[string]string
6060
RequestBody() io.ReadCloser
6161
ResponseWriter() http.ResponseWriter
62-
StdErr() io.ReadWriteCloser
6362
Model() *models.Call
6463
// For metrics/stats, add special accounting for time spent in customer code
6564
AddUserExecutionTime(dur time.Duration)

api/server/runner_fninvoke.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func (s *Server) fnInvoke(resp http.ResponseWriter, req *http.Request, app *mode
109109
}
110110
}
111111

112-
opts = append(opts, agent.WithWriter(rw))
112+
opts = append(opts, agent.WithWriter(writer))
113113
opts = append(opts, agent.WithStderrLogger())
114114
if trig != nil {
115115
opts = append(opts, agent.WithTrigger(trig))

0 commit comments

Comments
 (0)