Writing, Viewing, and Responding to Logs

Writing runtime logs

Cloud Functions includes simple runtime logging by default. Logs written to stdout or stderr will appear automatically in the Cloud Console. For more advanced logging, use the Cloud Logging Client Libraries.

As a default, the log payload is a simple text string, as shown in the following snippets. This string is stored in textPayload.


exports.helloWorld = (req, res) => {
  console.log('I am a log entry!');
  console.error('I am an error!');
Most log entries do not have an associated log level. These include:

  • Logs emitted using console.log(), console.info() , console.warn() or console.error()
  • Logs written directly to stdout or stderr

Internal system messages have the DEBUG log level.


def hello_world(data, context):
    """Background Cloud Function.
         data (dict): The dictionary with data specific to the given event.
         context (google.cloud.functions.Context): The event metadata.
    print('Hello, stdout!')
  • Logs to standard output or standard error do not have an associated log level.
  • Internal system messages have the DEBUG log level.


// Package helloworld provides a set of Cloud Functions samples.
package helloworld

import (

// HelloLogging logs messages.
func HelloLogging(w http.ResponseWriter, r *http.Request) {
	log.Println("This is stderr")
	fmt.Println("This is stdout")

	// Structured logging can be used to set severity levels.
	// See https://cloud.google.com/logging/docs/structured-logging.
	fmt.Println(`{"message": "This has ERROR severity", "severity": "error"}`)

	// cloud.google.com/go/logging can optionally be used for additional options.
  • Logs to stdout or stderr do not have an associated log level.
  • Internal system messages have the DEBUG log level.


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.logging.Logger;

public class LogHelloWorld implements HttpFunction {

  private static final Logger logger = Logger.getLogger(LogHelloWorld.class.getName());

  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    System.out.println("I am a log to stdout!");
    System.err.println("I am a log to stderr!");

    logger.info("I am an info log!");
    logger.warning("I am a warning log!");

    BufferedWriter writer = response.getWriter();
    writer.write("Messages successfully logged!");
  • Logs to stdout or stderr do not have an associated log level.
  • Internal system messages have the DEBUG log level.


using Google.Cloud.Functions.Framework;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;

namespace LogHelloWorld
    public class Function : IHttpFunction
        private readonly ILogger _logger;

        public Function(ILogger<Function> logger) =>
            _logger = logger;

        public async Task HandleAsync(HttpContext context)
            Console.WriteLine("I am a log to stdout!");
            Console.Error.WriteLine("I am a log to stderr!");

            _logger.LogInformation("I am an info log!");
            _logger.LogWarning("I am a warning log!");

            await context.Response.WriteAsync("Messages successfully logged!");
  • Text written to stdout (for example, via Console.WriteLine) and stderr (for example, via Console.Error.WriteLine) do not have a log level.
  • ASP.NET Core logging levels are mapped to Cloud Logging levels as follows:
    • LogLevel.Trace and LogLevel.Debug map to Cloud Logging DEBUG.
    • LogLevel.Information maps to Cloud Logging INFO.
    • LogLevel.Warning maps to Cloud Logging WARNING.
    • LogLevel.Error maps to Cloud Logging ERROR.
    • LogLevel.Critical maps to Cloud Logging CRITICAL.


require "functions_framework"

FunctionsFramework.http "log-helloworld" do |_request|
  # Any output sent to either stdout or stderr will be captured and written to
  # the function's logs.
  puts "Hello, stdout!"
  warn "Hello, stderr!"

  # Return the response body as a string.
  "Hello, world!"

Log entries do not have an associated log level.


use Psr\Http\Message\ServerRequestInterface;

function helloLogging(ServerRequestInterface $request): string
    // Code running in Google Cloud Functions itself writes log entries to
    // Cloud Logging. (Default log severity level is INFO.)
    $log = fopen('php://stderr', 'wb');
    fwrite($log, "Log entry from fwrite().\n");

    // You can also specify a severity level explicitly using structured logs.
    // See this page for a list of log severity values:
    //   https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity
    fwrite($log, json_encode([
      'message' => 'Structured log with error severity',
      'severity' => 'error'
    ]) . PHP_EOL);

    // This doesn't log anything
    error_log('error_log does not log in Cloud Functions!');

    // This will log an error message and immediately terminate the function execution
    // trigger_error('fatal errors are logged!');

    // For HTTP functions, this is added to the HTTP response
    // For CloudEvent functions, this does nothing
    var_dump('var_dump goes to HTTP response for HTTP functions');

    // You can also dump variables using var_export() and forward
    // the resulting string to Cloud Logging via an fwrite() call.
    $entry = var_export('var_export output can be captured.', true);
    fwrite($log, $entry);

    // Functions must return a String or PSR-7 Response object
    return '';

Writing structured logs

The default text logs described above do not have an associated log level. If you want to include log levels, or other specific fields, in your log entries, you can use structured data instead, in the form of a single line of serialized JSON. This line is picked up and parsed by Cloud Logging and is placed into jsonPayload instead of textPayload. The data is constructed as a JSON dictionary. The snippets below demonstrate creating these log entries.


// Uncomment and populate this variable in your code:
// $project = 'The project ID of your function or Cloud Run service';

// Build structured log messages as an object.
const globalLogFields = {};

// Add log correlation to nest all log messages beneath request log in Log Viewer.
// (This only works for HTTP-based invocations where `req` is defined.)
if (typeof req !== 'undefined') {
  const traceHeader = req.header('X-Cloud-Trace-Context');
  if (traceHeader && project) {
    const [trace] = traceHeader.split('/');
    ] = `projects/${project}/traces/${trace}`;

// Complete a structured log entry.
const entry = Object.assign(
    severity: 'NOTICE',
    message: 'This is the default display field.',
    // Log viewer accesses 'component' as 'jsonPayload.component'.
    component: 'arbitrary-property',

// Serialize to a JSON string and output.


Structured logging support is available in Python 3.8 and later.

# Uncomment and populate this variable in your code:
# PROJECT = 'The project ID of your Cloud Run service';

# Build structured log messages as an object.
global_log_fields = {}

# Add log correlation to nest all log messages.
trace_header = request.headers.get("X-Cloud-Trace-Context")

if trace_header and PROJECT:
    trace = trace_header.split("/")
    ] = f"projects/{PROJECT}/traces/{trace[0]}"

# Complete a structured log entry.
entry = dict(
    message="This is the default display field.",
    # Log viewer accesses 'component' as jsonPayload.component'.



The structure for each log entry is provided by an Entry type:

// Entry defines a log entry.
type Entry struct {
	Message  string `json:"message"`
	Severity string `json:"severity,omitempty"`
	Trace    string `json:"logging.googleapis.com/trace,omitempty"`

	// Logs Explorer allows filtering and display of this as `jsonPayload.component`.
	Component string `json:"component,omitempty"`

// String renders an entry structure to the JSON format expected by Cloud Logging.
func (e Entry) String() string {
	if e.Severity == "" {
		e.Severity = "INFO"
	out, err := json.Marshal(e)
	if err != nil {
		log.Printf("json.Marshal: %v", err)
	return string(out)

When an Entry struct is logged, the String method is called to marshal it to the JSON format expected by Cloud Logging:

func init() {
	// Disable log prefixes such as the default timestamp.
	// Prefix text prevents the message from being parsed as JSON.
	// A timestamp is added when shipping logs to Cloud Logging.

func indexHandler(w http.ResponseWriter, r *http.Request) {
	// Uncomment and populate this variable in your code:
	// projectID = "The project ID of your Cloud Run service"

	// Derive the traceID associated with the current request.
	var trace string
	if projectID != "" {
		traceHeader := r.Header.Get("X-Cloud-Trace-Context")
		traceParts := strings.Split(traceHeader, "/")
		if len(traceParts) > 0 && len(traceParts[0]) > 0 {
			trace = fmt.Sprintf("projects/%s/traces/%s", projectID, traceParts[0])

		Severity:  "NOTICE",
		Message:   "This is the default display field.",
		Component: "arbitrary-property",
		Trace:     trace,

	fmt.Fprintln(w, "Hello Logger!")


Enable JSON logging with Logback and SLF4J by enabling the Logstash JSON Encoder in your logback.xml configuration.

// Build structured log messages as an object.
Object globalLogFields = null;

// Add log correlation to nest all log messages beneath request log in Log Viewer.
// TODO(developer): delete this code if you're creating a Cloud
//                  Function and it is *NOT* triggered by HTTP.
String traceHeader = req.headers("x-cloud-trace-context");
if (traceHeader != null && project != null) {
  String trace = traceHeader.split("/")[0];
  globalLogFields =
          String.format("projects/%s/traces/%s", project, trace));
// -- End log correlation code --

// Create a structured log entry using key value pairs.
    "This is the default display field.",
    kv("component", "arbitrary-property"),
    kv("severity", "NOTICE"),
  <appender name="jsonConsoleAppender" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="net.logstash.logback.encoder.LogstashEncoder">
      <!-- Ignore default logging fields -->
  <root level="INFO">
    <appender-ref ref="jsonConsoleAppender"/>

Processing special JSON fields in messages

When you provide structured data as a JSON dictionary, some special fields are stripped from the jsonPayload and are written to the corresponding field in the generated LogEntry, as described in the documentation for special fields.

For example, if your JSON includes a severity property, it is removed from the jsonPayload and appears instead as the log entry's severity. The message property is used as the main display text of the log entry if present.

Viewing runtime logs

Using the command-line tool

Logs for Cloud Functions are viewable in the Cloud Logging UI, and via the gcloud command-line tool.

To view logs with the gcloud tool, use the logs read command:

gcloud functions logs read

To view the logs for a specific function, provide the function name as an argument:

gcloud functions logs read FUNCTION_NAME

You can even view the logs for a specific execution:

gcloud functions logs read FUNCTION_NAME --execution-id EXECUTION_ID

For the full range of log viewing options, view the help for logs read:

gcloud functions logs read --help

Using the Logging dashboard

You can also view runtime logs for Cloud Functions from the Cloud Console.

Using the Logging API

Runtime logs can also be written and retrieved through the Cloud Logging API. The Cloud Logging Client Libraries provide an idiomatic interface to the Logging API:


For more information, see the Node.js Client Library reference.
// Imports the Google Cloud client library
const {Logging} = require('@google-cloud/logging');

// Creates a client
const logging = new Logging();

 * TODO(developer): Uncomment the following line to run the code.
// const logName = 'Name of the log from which to list entries, e.g. my-log';

const log = logging.log(logName);

async function printEntryMetadata() {
  // List the most recent entries for a given log
  // See https://googleapis.dev/nodejs/logging/latest/Logging.html#getEntries
  const [entries] = await log.getEntries();
  entries.forEach(entry => {
    const metadata = entry.metadata;
    console.log(`${metadata.timestamp}:`, metadata[metadata.payload]);


For more information, see the Python Client Library reference.
def list_entries(logger_name):
    """Lists the most recent entries for a given logger."""
    logging_client = logging.Client()
    logger = logging_client.logger(logger_name)

    print("Listing entries for logger {}:".format(logger.name))

    for entry in logger.list_entries():
        timestamp = entry.timestamp.isoformat()
        print("* {}: {}".format(timestamp, entry.payload))


For more information, see the Go Client Library reference.
var entries []*logging.Entry
const name = "log-example"
lastHour := time.Now().Add(-1 * time.Hour).Format(time.RFC3339)

iter := adminClient.Entries(ctx,
	// Only get entries from the "log-example" log within the last hour.
	logadmin.Filter(fmt.Sprintf(`logName = "projects/%s/logs/%s" AND timestamp > "%s"`, projID, name, lastHour)),
	// Get most recent entries first.

// Fetch the most recent 20 entries.
for len(entries) < 20 {
	entry, err := iter.Next()
	if err == iterator.Done {
		return entries, nil
	if err != nil {
		return nil, err
	entries = append(entries, entry)
return entries, nil


For more information, see the Java Client Library reference.
import com.google.api.gax.paging.Page;
import com.google.cloud.logging.LogEntry;
import com.google.cloud.logging.Logging;
import com.google.cloud.logging.Logging.EntryListOption;
import com.google.cloud.logging.LoggingOptions;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;

public class ListLogEntries {

  public static void main(String[] args) throws Exception {
    // TODO(developer): Replace the variable value with valid log name before running the sample
    // or provide it as an argument.
    String logName = args.length > 0 ? args[0] : "test-log";

    try (Logging logging = LoggingOptions.getDefaultInstance().getService()) {

      // When composing a filter, using indexed fields, such as timestamp, resource.type, logName
      // and
      // others can help accelerate the results
      // Full list of indexed fields here:
      // https://cloud.google.com/logging/docs/view/advanced-queries#finding-quickly
      // This sample restrict the results to only last minute to minimize number of API calls
      Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
      calendar.add(Calendar.MINUTE, -1);
      DateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
      String logFilter =
              + logging.getOptions().getProjectId()
              + "/logs/"
              + logName
              + " AND timestamp>=\""
              + rfc3339.format(calendar.getTime())
              + "\"";

      // List all log entries
      Page<LogEntry> entries = logging.listLogEntries(EntryListOption.filter(logFilter));
      while (entries != null) {
        for (LogEntry logEntry : entries.iterateAll()) {
        entries = entries.getNextPage();


private void ListLogEntries(string logId)
    var client = LoggingServiceV2Client.Create();
    LogName logName = new LogName(s_projectId, logId);
    ProjectName projectName = new ProjectName(s_projectId);
    var results = client.ListLogEntries(Enumerable.Repeat(projectName, 1), $"logName={logName.ToString()}",
        "timestamp desc", callSettings: _retryAWhile);
    foreach (var row in results)


require "google/cloud/logging"

# log_name = "my_log_name"
logging = Google::Cloud::Logging.new
entries = logging.entries filter: "logName:#{log_name}",
                          max:    1000,
                          order:  "timestamp desc"

entries.each do |entry|
  puts "[#{entry.timestamp}] #{entry.log_name} #{entry.payload.inspect}"


use Google\Cloud\Logging\LoggingClient;

/** Return an iterator for listing log entries.
 * @param string $projectId The Google project ID.
 * @param string $loggerName The name of the logger.
 * @return ItemIterator<Google\Cloud\Logging\Entry>
function list_entries($projectId, $loggerName)
    $logging = new LoggingClient(['projectId' => $projectId]);
    $loggerFullName = sprintf('projects/%s/logs/%s', $projectId, $loggerName);
    $oneDayAgo = date(\DateTime::RFC3339, strtotime('-24 hours'));
    $filter = sprintf(
        'logName = "%s" AND timestamp >= "%s"',
    $options = [
        'filter' => $filter,
    $entries = $logging->entries($options);

    // Print the entries
    foreach ($entries as $entry) {
        /* @var $entry \Google\Cloud\Logging\Entry */
        $entryInfo = $entry->info();
        if (isset($entryInfo['textPayload'])) {
            $entryText = $entryInfo['textPayload'];
        } else {
            $entryPayload = [];
            foreach ($entryInfo['jsonPayload'] as $key => $value) {
                $entryPayload[] = "$key: $value";
            $entryText = '{' . implode(', ', $entryPayload) . '}';
        printf('%s : %s' . PHP_EOL, $entryInfo['timestamp'], $entryText);

For additional logging options for Java, see Java Logging.

Responding to runtime logs

You can respond to Cloud Logging events by forwarding their logs to a Cloud Function. For more information, see the Second-Party Triggers with Cloud Logging page.

Viewing build image logs

You can also see the logs for the build image step of the deployment process. Follow the link for more information.