Escribe, visualiza y responde registros

Escribe registros del entorno de ejecución

De forma predeterminada, Cloud Functions incluye registros sencillos sobre el entorno de ejecución. Los registros que se escriban en stdout o stderr aparecerán de forma automática en Cloud Console. Para obtener un registro más avanzado, usa las bibliotecas cliente de Cloud Logging.

De forma predeterminada, la carga útil del registro es una string de texto simple, como se muestra en los siguientes fragmentos. Esta string se almacena en textPayload.

Node.js

exports.helloWorld = (req, res) => {
  console.log('I am a log entry!');
  console.error('I am an error!');
  res.end();
};
La mayoría de las entradas de registro no tienen un nivel de registro asociado. Estos incluyen los siguientes:

  • Registros emitidos con console.log(), console.info(), console.warn() o console.error()
  • Registros escritos directamente en stdout o stderr

Los mensajes internos del sistema tienen el nivel de registro DEBUG.

Python

def hello_world(data, context):
    """Background Cloud Function.
    Args:
         data (dict): The dictionary with data specific to the given event.
         context (google.cloud.functions.Context): The event metadata.
    """
    print('Hello, stdout!')
  • Los registros escritos en los flujos estándares de salida o error no tienen un nivel de registro asociado.
  • Los mensajes internos del sistema tienen el nivel de registro DEBUG.

Go


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

import (
	"fmt"
	"log"
	"net/http"
)

// 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.
}
  • Los registros escritos en stdout o stderr no tienen un nivel de registro asociado.
  • Los mensajes internos del sistema tienen el nivel de registro DEBUG.

Java


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());

  @Override
  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!");
  }
}
  • Los registros escritos en stdout o stderr no tienen un nivel de registro asociado.
  • Los mensajes internos del sistema tienen el nivel de registro DEBUG.

C#

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!");
        }
    }
}
  • El texto escrito en stdout (por ejemplo, a través de Console.WriteLine) y stderr (por ejemplo, a través de Console.Error.WriteLine) no tiene un nivel de registro.
  • Los niveles de registro de ASP.NET Core se mapean a los niveles de Cloud Logging de la siguiente manera:
    • LogLevel.Trace y LogLevel.Debug map a DEBUG de Cloud Logging
    • LogLevel.Information se mapea a INFO de Cloud Logging
    • LogLevel.Warning se mapea a WARNING de Cloud Logging
    • LogLevel.Error se mapea a ERROR de Cloud Logging
    • LogLevel.Critical se mapea a CRITICAL de Cloud Logging

Escribe registros estructurados

Los registros de texto predeterminados descritos con anterioridad no tienen un nivel de registro asociado. Si deseas incluir niveles de registro, o bien otros campos específicos, en las entradas de registro, puedes usar datos estructurados en forma de una sola línea de JSON serializado. Cloud Logging toma y analiza esta línea, y la coloca en jsonPayload en lugar de textPayload. Los datos se construyen como un diccionario JSON. Los siguientes fragmentos demuestran cómo crear estas entradas de registro.

Node.js


// Uncomment and populate this variable in your code:
// $project = 'The project ID of your 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.
const traceHeader = req.header('X-Cloud-Trace-Context');
if (traceHeader && project) {
  const [trace] = traceHeader.split('/');
  globalLogFields[
    'logging.googleapis.com/trace'
  ] = `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',
  },
  globalLogFields
);

// Serialize to a JSON string and output.
console.log(JSON.stringify(entry));

Python

# 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
# beneath request log in Log Viewer.
trace_header = request.headers.get('X-Cloud-Trace-Context')

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

# Complete a structured log entry.
entry = dict(severity='NOTICE',
             message='This is the default display field.',
             # Log viewer accesses 'component' as jsonPayload.component'.
             component='arbitrary-property',
             **global_log_fields)

print(json.dumps(entry))

Go

Un tipo de Entry proporciona la estructura para cada entrada de registro:


// 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"`

	// Cloud Log Viewer 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)
}

Cuando se registra una estructura de Entry, se llama al método String para serializarla según el formato JSON que espera 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.
	log.SetFlags(0)
}

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])
		}
	}

	log.Println(Entry{
		Severity:  "NOTICE",
		Message:   "This is the default display field.",
		Component: "arbitrary-property",
		Trace:     trace,
	})

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

Java

Para habilitar el registro JSON con Logback y SLF4J, debes habilitar el codificador de JSON de Logstash en la configuración logback.xml.

// Build structured log messages as an object.
Object globalLogFields = null;
// Add log correlation to nest all log messages beneath request log in Log Viewer.
String traceHeader = req.headers("x-cloud-trace-context");
if (traceHeader != null && project != null) {
  String trace = traceHeader.split("/")[0];
  globalLogFields =
      kv(
          "logging.googleapis.com/trace",
          String.format("projects/%s/traces/%s", project, trace));
}
// Create a structured log entry using key value pairs.
logger.error(
    "This is the default display field.",
    kv("component", "arbitrary-property"),
    kv("severity", "NOTICE"),
    globalLogFields);
<configuration>
  <appender name="jsonConsoleAppender" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="net.logstash.logback.encoder.LogstashEncoder">
      <!-- Ignore default logging fields -->
      <fieldNames>
        <timestamp>[ignore]</timestamp>
        <version>[ignore]</version>
        <logger>[ignore]</logger>
        <thread>[ignore]</thread>
        <level>[ignore]</level>
        <levelValue>[ignore]</levelValue>
      </fieldNames>
    </encoder>
  </appender>
  <root level="INFO">
    <appender-ref ref="jsonConsoleAppender"/>
  </root>
</configuration>

Procesa campos JSON especiales en mensajes

Cuando proporcionas datos estructurados como un diccionario JSON, algunos campos especiales se extraen de jsonPayload y se escriben en el campo correspondiente en el LogEntry generado, como se describe en la documentación de campos especiales.

Por ejemplo, si el JSON incluye una propiedad severity, se quita de jsonPayload y aparece como la severity de la entrada de registro. La propiedad message se usa como el texto de visualización principal de la entrada de registro, si está presente.

Visualiza los registros del entorno de ejecución

Usa la herramienta de línea de comandos

Los registros de Cloud Functions se pueden ver en la IU de Cloud Logging y a través de la herramienta de línea de comandos de gcloud.

Para ver los registros con la herramienta de gcloud, usa el comando logs read:

gcloud functions logs read

Para ver los registros de una función específica, proporciona el nombre de la función como un argumento:

gcloud functions logs read FUNCTION_NAME

Incluso puedes ver los registros para una ejecución específica:

gcloud functions logs read FUNCTION_NAME --execution-id EXECUTION_ID

Para conocer la gama completa de opciones de visualización de registros, vea la ayuda de logs read:

gcloud functions logs read --help

Usa el panel de Logging

También puedes ver los registros del entorno de ejecución de Cloud Functions desde Cloud Console.

Usa la API de Logging

Los registros del entorno de ejecución también se pueden escribir y recuperar a través de la API de Cloud Logging. Las bibliotecas cliente de Cloud Logging proporcionan una interfaz idiomática a la API de Logging:

Node.js

Para obtener más información, consulta la referencia de la biblioteca cliente de Node.js.
// 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();
  console.log('Logs:');
  entries.forEach(entry => {
    const metadata = entry.metadata;
    console.log(`${metadata.timestamp}:`, metadata[metadata.payload]);
  });
}
printEntryMetadata();

Python

Para obtener más información, consulta la referencia de la biblioteca cliente de Python.
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))

Go

Para obtener más información, consulta la referencia de la biblioteca cliente de Go.
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.
	logadmin.NewestFirst(),
)

// 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

Java

Para obtener más información, consulta la referencia de la biblioteca cliente de Java.
// Instantiates a client
LoggingOptions options = LoggingOptions.getDefaultInstance();

String logName = args[0];

try (Logging logging = options.getService()) {

  String logFilter =
      "logName=projects/"
          + options.getProjectId()
          + "/logs/"
          + logName
          + " AND timestamp>=\"2020-09-01T00:00:00.000Z\"";

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

C#

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)
    {
        Console.WriteLine($"{row.TextPayload.Trim()}");
    }
}

Si quieres obtener más opciones de registro para Java, consulta Java Logging.

Responde los registros del entorno de ejecución

Para responder a los eventos de Cloud Logging reenvía sus registros a una función de Cloud Functions. Para obtener más información, consulta la página Activadores secundarios con Cloud Logging.

Visualiza registros de compilación de imágenes

También puedes ver los registros del paso que abarca la compilación de imágenes del proceso de implementación. Consulta el vínculo para obtener más información.