Skip to content

Commit 56d5e44

Browse files
committed
Control runtime log level via environment variable (#33)
1 parent 4159e42 commit 56d5e44

File tree

6 files changed

+34
-14
lines changed

6 files changed

+34
-14
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,10 @@ See `awspack/` for an example.
231231
The `build.sh` script is used to run the docker container and copy sources to your machine.
232232
The `entrypoint.sh` script is used for installing packages inside the container.
233233

234+
### Debugging
235+
236+
In order to make the runtime log debugging messages, you can set the environment variable `LOGLEVEL` to `DEBUG`.
237+
234238
## Limitations
235239

236240
AWS Lambda is limited to running with 3GB RAM and must finish within 15 minutes.

runtime/src/bootstrap.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ tryCatch({
33
function_name <- initializeRuntime()
44
while (TRUE) {
55
handle_request(function_name)
6+
logReset()
67
rm(list=ls())
78
source('/opt/runtime.R')
89
function_name <- initializeRuntime()

runtime/src/runtime.R

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ error_to_payload <- function(error) {
77
}
88

99
post_error <- function(error, url) {
10-
logerror(error)
10+
logerror(error, logger = 'runtime')
1111
res <- POST(url,
1212
add_headers("Lambda-Runtime-Function-Error-Type" = "Unhandled"),
1313
body = error_to_payload(error),
1414
encode = "json")
15-
logdebug("Posted result:\n%s", to_str(res))
15+
logdebug("Posted result:\n%s", to_str(res), logger = 'runtime')
1616
}
1717

1818
get_source_file_name <- function(file_base_name) {
@@ -28,22 +28,33 @@ get_source_file_name <- function(file_base_name) {
2828

2929
invoke_lambda <- function(EVENT_DATA, function_name) {
3030
params <- fromJSON(EVENT_DATA)
31-
logdebug("Invoking function '%s' with parameters:\n%s", function_name, to_str(params))
31+
logdebug("Invoking function '%s' with parameters:\n%s", function_name, to_str(params), logger = 'runtime')
3232
result <- do.call(function_name, params)
33-
logdebug("Function returned:\n%s", to_str(result))
33+
logdebug("Function returned:\n%s", to_str(result), logger = 'runtime')
3434
return(result)
3535
}
3636

37+
initializeLogging <- function() {
38+
library(logging)
39+
40+
basicConfig()
41+
addHandler(writeToConsole, logger='runtime')
42+
log_level <- Sys.getenv('LOGLEVEL', unset = NA)
43+
if (!is.na(log_level)) {
44+
setLevel(log_level, 'runtime')
45+
}
46+
}
47+
3748
initializeRuntime <- function() {
3849
library(httr)
3950
library(jsonlite)
40-
library(logging)
4151

52+
initializeLogging()
4253
HANDLER <- Sys.getenv("_HANDLER")
4354
HANDLER_split <- strsplit(HANDLER, ".", fixed = TRUE)[[1]]
4455
file_base_name <- HANDLER_split[1]
4556
file_name <- get_source_file_name(file_base_name)
46-
logdebug("Sourcing '%s'", file_name)
57+
logdebug("Sourcing '%s'", file_name, logger = 'runtime')
4758
source(file_name)
4859
function_name <- HANDLER_split[2]
4960
if (!exists(function_name, mode = "function")) {
@@ -69,7 +80,7 @@ throwRuntimeError <- function(error, REQUEST_ID) {
6980
postResult <- function(result, REQUEST_ID) {
7081
url <- paste0(API_ENDPOINT, "invocation/", REQUEST_ID, "/response")
7182
res <- POST(url, body = toJSON(result, auto_unbox = TRUE), encode = "raw", content_type_json())
72-
logdebug("Posted result:\n%s", to_str(res))
83+
logdebug("Posted result:\n%s", to_str(res), logger = 'runtime')
7384
}
7485

7586
handle_request <- function(function_name) {

test-template.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ Resources:
5858
Properties:
5959
Handler: script.handler_with_debug_logging
6060
CodeUri: tests/R/
61+
Environment:
62+
Variables:
63+
LOGLEVEL: DEBUG
6164
FunctionName: !Sub LoggingFunction-${Version}
6265
MatrixFunction:
6366
Type: 'AWS::Serverless::Function'

tests/R/script.R

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,5 @@ handler_with_variable_arguments <- function(...) {
1313
handler_as_variable <- "foo"
1414

1515
handler_with_debug_logging <- function(x) {
16-
basicConfig(level='DEBUG')
1716
return(1)
1817
}

tests/test_runtime.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ def test_debug_logging(self):
6161
result = json.loads(raw_payload)
6262
self.assertEqual(1, result)
6363
log = base64.b64decode(response['LogResult']).decode('utf-8')
64-
self.assertIn("Invoking function 'handler_with_debug_logging' with parameters:\n$x\n[1] 1", log)
65-
self.assertIn("Function returned:\n[1] 1", log)
66-
self.assertIn("Sourcing 'script.R'", log)
64+
self.assertIn("runtime:Sourcing 'script.R'", log)
65+
self.assertIn("runtime:Invoking function 'handler_with_debug_logging' with parameters:\n$x\n[1] 1", log)
66+
self.assertIn("runtime:Function returned:\n[1] 1", log)
67+
self.assertIn("runtime:Posted result:\n", log)
6768

6869
@unittest.skipIf(is_local(), 'Lambda local does not support log retrieval')
6970
def test_no_debug_logging(self):
@@ -76,9 +77,10 @@ def test_no_debug_logging(self):
7677
result = json.loads(raw_payload)
7778
self.assertEqual(2, result)
7879
log = base64.b64decode(response['LogResult']).decode('utf-8')
79-
self.assertNotIn("Invoking function 'handler_with_debug_logging' with parameters:\n$x\n[1] 1", log)
80-
self.assertNotIn("Function returned:\n[1] 1", log)
81-
self.assertNotIn("Sourcing 'script.R'", log)
80+
self.assertNotIn("Sourcing ", log)
81+
self.assertNotIn("Invoking function ", log)
82+
self.assertNotIn("Function returned:", log)
83+
self.assertNotIn("Posted result:", log)
8284

8385
@unittest.skipIf(is_local(), 'Lambda local does not pass errors properly')
8486
def test_missing_source_file(self):

0 commit comments

Comments
 (0)