• Guide Content

Serverless Logging: Challenges, Methods, and Best Practices

What is Serverless Logging? 

Serverless computing is a cloud computing execution model in which the cloud provider dynamically manages the allocation of machine resources. It allows developers to build and run applications and services without having to think about infrastructure.

Serverless logging is crucial for debugging, monitoring, and maintaining serverless applications, and works quite differently than in traditional applications. There are several ways to log the activity of serverless functions:

  • Use a logging library: Many programming languages have libraries that can be used to write log entries to a file, database, or other destination. For example, Python has the built-in logging module, and Node.js has the popular Winston library.
  • Use a cloud provider’s logging service: Cloud providers that offer serverless computing platforms, such as AWS, Azure, and Google Cloud, often have their own logging services that can be used to store and manage log entries. For example, AWS Lambda integrates with Amazon CloudWatch Logs, Azure Functions integrates with Azure Log Analytics, and Google Cloud Functions integrates with Stackdriver Logging.
  • Use a third-party logging service: There are also many third-party logging services that can be used to store and manage log entries from serverless functions, including services built for serverless environments, such as Lumigo.

This is part of a series of articles about serverless monitoring.

In this article:

Difference Between Traditional Logging and Serverless Logging

Logging serverless functions is similar to logging traditional applications in many ways, but there are also some differences:

  • Scale: One of the main differences is that serverless functions can scale up and down very quickly in response to changes in demand, which means that the logging system must be able to handle a potentially large volume of log entries.
  • Context: Serverless functions are typically invoked in response to a specific trigger, such as a user action or a change in data, which means that it may be important to include context about the trigger in the log entries.
  • Pay-per-use: Serverless functions are typically charged on a pay-per-use basis, which means that it may be important to consider the cost of logging when designing a serverless application.

Serverless Logging Challenges 

There are several key challenges involved when logging serverless applications:

  • Scale: Serverless applications can scale up and down very quickly in response to changes in demand, which means that the logging system must be able to handle a potentially large volume of log entries.
  • Context: Serverless functions are typically invoked in response to a specific trigger, such as a user action or a change in data, which means that it may be important to include context about the trigger in the log entries.
  • Ephemeral functions: Serverless functions are typically ephemeral, meaning that they are created and destroyed dynamically as needed. This can make it challenging to store log data and maintain a consistent logging context across multiple invocations of a function.
  • Stateless functions: Serverless functions are typically stateless, meaning that they do not maintain any state between invocations. This can make it difficult to track the progress of a long-running task or process.

What To Log When Using Serverless?

In serverless applications, there are several types of information that you may want to log:

  • Invocations and event inputs: It can be helpful to log information about the invocations of your serverless functions, including the time of the invocation, the function that was invoked, and the event that triggered the invocation. You may also want to log the input data that was passed to the function, such as the payload of an HTTP request or the data that was modified in a database.
  • Response payloads: It can be useful to log the output of your serverless functions, such as the payload of an HTTP response or the data that was written to a database. This can help you to track the results of your functions and to identify any issues that may need to be addressed.
  • Performance levels: It can be important to monitor the performance of your serverless functions, including the execution time and the resources that are consumed. You may want to log information about the performance of your functions, such as the execution time, the memory usage, and the number of requests per second.
  • Authentication requests: If your serverless functions require authentication, you may want to log information about the authentication requests, including the time of the request, the user or service that made the request, and the outcome of the request (e.g., whether the request was successful or failed). This can help you to track the security of your functions and to identify any issues that may need to be addressed.

Serverless Logging Methods

Synchronous Logging

Synchronous logging is a logging method in which log entries are generated and written to a destination in real-time, as the software or system is running. This is in contrast to asynchronous logging, in which log entries are generated and queued for writing at a later time.

Here is an example of how to use synchronous logging with Python’s built-in logging module:

import logging

# Set up a logger
logger = logging.getLogger(__name__)

def my_function(event, context):
    # Write a log entry
    logger.info("Processing request")

    # Do some work
    result = do_some_work(event)

    # Write another log entry
    logger.info("Request processed successfully")

def do_some_work(event):
    for a in range(20000):
       for b in range(20):
           sum=a*b

if __name__ == "__main__":
    my_function(None, None)

In this example, the logger writes two log entries: one when the function starts processing the request, and one when the function finishes processing the request. The log entries are written to the default logging destination, which is typically a file or the console.

Using synchronous logging has the advantage of providing a real-time record of what is happening in the software or system, which can be helpful for debugging, monitoring, and performance analysis. However, it can also introduce performance overhead, as the log entries must be written in real-time, which can slow down the software or system.

To minimize this overhead, it is important to design the logging system to be as efficient as possible, and to minimize the number of log entries that are written, using log levels, filtering or sampling techniques.

Asynchronous Logging

Asynchronous logging is a logging method in which log entries are generated and queued for writing at a later time, rather than being written in real-time as the software or system is running. This can help to minimize the performance overhead of logging, as log entries are not written immediately and do not block the execution of the software or system.

The following example uses the Python jk-asyhncio-logging library. You can install it using this command: 

pip install jk-asyncio-logging

Here is the code:

import asyncio
import logging
import jk_asyncio_logging

# Set up a logger
logger = logging.getLogger(__name__)

# Create a function that calls an async method to perform tasks

async def my_function(event, context):
    # Write a log entry
    logger.info("Processing request")
    
    # Do some work
    result = await do_some_work_async(event)
    
    # Write another log entry
    logger.info("Request processed successfully")
    
    return result

# Create an async function that does some random task

async def do_some_work_async(event):
	for i in range(100):
		for j in range(200):
			i*j
			
	# Print the log information
	
	await log.info("This is a test for INFO.")
	
	return 1

# Instantiate the logger object
log = jk_asyncio_logging.AsyncioConsoleLogger.create(logMsgFormatter=jk_asyncio_logging.COLOR_LOG_MESSAGE_FORMATTER)


loop = asyncio.get_event_loop()
loop.run_until_complete(my_function(None, None))

In this example, the logger writes two log entries: one when the function starts processing the request, and one when the function finishes processing the request. The log entries are not written immediately, but are queued for writing at a later time.

Using asynchronous logging can help to minimize the performance overhead of logging, as log entries are not written immediately and do not block the execution of the software or system. However, it can also make it more difficult to track the progress of a task or process in real-time, as log entries are not written immediately.

4 Serverless Logging Best Practices 

Here are some best practices for logging in serverless applications:

  • Structure log values: It can be helpful to structure your log values in a consistent and meaningful way, using a structured logging format such as JSON. This can make it easier to parse and analyze your log entries, and to extract specific values or fields.
  • Use log levels: It can be useful to use log levels to control the verbosity of your log entries, and to only log entries at certain levels (such as “error” or “warning”) in production environments. This can help to reduce the volume of log entries and to focus on the most important or critical messages.
  • Apply correlation IDs to logs: It can be helpful to use correlation IDs to link log entries that belong to the same request or process, especially if your serverless functions are invoked asynchronously or in parallel. This can make it easier to track the progress of a task or process and to identify any issues that may arise.
  • Sample logs to reduce noise: If you are generating a large volume of log entries, it can be helpful to use sampling techniques to reduce the volume of log entries and to focus on a representative sample. This can help to reduce the noise in your logs and to make it easier to identify patterns and trends.

Serverless Monitoring with Lumigo

Lumigo is a distributed tracing platform purpose-built for troubleshooting microservices in production. Developers building serverless apps with  AWS Lambda and other serverless services use Lumigo to monitor, trace and troubleshoot their serverless applications. Deployed with no changes and automated in one-click, Lumigo stitches together every interaction between micro and managed services into end-to-end stack traces, giving complete visibility into serverless environments. Using Lumigo to monitor and troubleshoot their applications, developers get:

  • End-to-end virtual stack traces across every micro and managed service that makes up a serverless application, in context
  • API visibility that makes all the data passed between services available and accessible, making it possible to perform root cause analysis without digging through logs 
  • Distributed tracing that is deployed with no code and automated in one click 
  • Unified platform to explore and query across microservices, see a real-time view of applications, and optimize performance

Learn more about Lumigo