Registo e visualização de registos no Knative Serving

Esta página descreve os registos disponíveis quando usa o Knative Serving e como ver e escrever registos.

O Knative Serving tem dois tipos de registos:

  • Registos de pedidos: registos de pedidos enviados para serviços do Knative Serving. Estes registos são criados automaticamente.
  • Registos de contentores: registos emitidos a partir das instâncias de contentores, normalmente do seu próprio código, escritos em localizações suportadas, conforme descrito no artigo Escrever registos de contentores.

Ativar registos

Os registos Google Cloud são enviados automaticamente para o Cloud Logging. Para o Google Distributed Cloud, tem de ativar primeiro os registos.

Ver registos

Pode ver os registos do seu serviço de duas formas:

  • Use a página de publicação do Knative na Google Cloud consola
  • Use o Explorador de registos do Cloud Logging na Google Cloud consola.

Ambos os métodos de visualização examinam os mesmos registos armazenados no Cloud Logging, mas o Logs Explorer do Cloud Logging oferece mais detalhes e capacidades de filtragem.

Ver registos no Knative Serving

Para ver os registos na página Knative Serving:

  1. Aceda ao Knative Serving

  2. Clique no serviço pretendido na lista apresentada.

  3. Clique no separador REGISTOS para obter os registos de pedidos e contentores de todas as revisões deste serviço. Pode filtrar por nível de gravidade do registo.

Ver registos no Cloud Logging

Para ver os registos de envio do Knative no explorador de registos do Cloud Logging:

  1. Aceda à página Logs Explorer na Google Cloud consola.

  2. Selecione um Google Cloud projeto existente na parte superior da página ou crie um novo projeto.

  3. Nos menus pendentes, selecione o recurso: Kubernetes Container.

Para mais informações, consulte o artigo Usar o Explorador de registos.

Ver registos no Cloud Code

Para ver os seus registos no Cloud Code, leia os guias do IntelliJ e do Visual Studio Code.

Ler registos de forma programática

Se quiser ler os registos de forma programática, pode usar um destes métodos:

Escrever registos do contentor

Quando escreve registos a partir do seu serviço, estes são recolhidos automaticamente pelo Cloud Logging, desde que sejam escritos em qualquer uma das seguintes localizações:

Espera-se que a maioria dos programadores escreva registos usando a saída padrão e o erro padrão.

Os registos de contentores escritos nestas localizações suportadas são automaticamente associados ao serviço, à revisão e à localização do Knative Serving.

Usar texto simples vs. JSON estruturado nos registos

Quando escreve registos, pode enviar uma string de texto simples ou uma única linha de JSON serializado, também denominada dados "estruturados". Esta informação é recolhida e analisada pelo Cloud Logging e é colocada em jsonPayload. Por outro lado, a mensagem de texto simples é colocada em textPayload.

Escrever registos estruturados

O fragmento seguinte mostra como escrever entradas de registo estruturadas. Também mostra como correlacionar mensagens de registo com o registo de pedidos correspondente.

Node.js


// Uncomment and populate this variable in your code:
// const 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('/');
    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.
# This is only relevant in HTTP-based contexts, and is ignored elsewhere.
# (In particular, non-HTTP-based Cloud Functions.)
request_is_defined = "request" in globals() or "request" in locals()
if request_is_defined and request:
    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))

Ir

A estrutura de cada entrada de registo é fornecida por um tipo Entry:


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

Quando uma estrutura de entrada é registada, o método String é chamado para a serializar no formato JSON esperado pelo 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

Ative o registo JSON com o Logback e o SLF4J ativando o Logstash JSON Encoder na sua configuração 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.
// 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 =
      kv(
          "logging.googleapis.com/trace",
          String.format("projects/%s/traces/%s", project, trace));
}
// -- End log correlation code --

// Create a structured log entry using key value pairs.
// For instantiating the "logger" variable, see
// https://cloud.google.com/run/docs/logging#run_manual_logging-java
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>

Campos JSON especiais em mensagens

Quando fornece um registo estruturado como um dicionário JSON, alguns campos especiais são removidos do jsonPayload e são escritos no campo correspondente no LogEntry gerado, conforme descrito na documentação para campos especiais.

Por exemplo, se o seu JSON incluir uma propriedade severity, esta é removida de jsonPayload e aparece como severity da entrada do registo. A propriedade message é usada como o texto de apresentação principal da entrada do registo, se estiver presente. Para mais informações sobre propriedades especiais, leia a secção Recurso de registo abaixo.

Correlacionar os registos do contentor com um registo de pedidos

No Explorador de registos, os registos correlacionados pelo mesmo trace são visíveis no formato "principal-secundário": quando clica no ícone de triângulo à esquerda da entrada do registo de pedidos, os registos do contentor relacionados com esse pedido são apresentados aninhados no registo de pedidos.

Os registos de contentores não são automaticamente correlacionados com os registos de pedidos, a menos que use uma biblioteca de cliente do Cloud Logging. Para correlacionar os registos de contentores com os registos de pedidos sem usar uma biblioteca de cliente, pode usar uma linha de registo JSON estruturada que contenha um campo logging.googleapis.com/trace com o identificador de rastreio extraído do cabeçalho X-Cloud-Trace-Context, conforme mostrado no exemplo acima para registo estruturado.

Controlar a utilização de recursos do registo de pedidos

Os registos de pedidos são criados automaticamente. Embora não possa controlar a quantidade de registos de pedidos diretamente a partir do Knative Serving, pode usar a funcionalidade de exclusão de registos do Cloud Logging.

Uma nota sobre os agentes de registo

Se usou o Cloud Logging com determinados Google Cloud produtos, como o Compute Engine, pode ter usado agentes de registo do Cloud Logging. O Knative serving não usa agentes de registo porque tem suporte incorporado para a recolha de registos.

Recurso de registo

Se clicar numa entrada do registo no Logs Explorer, é aberta uma entrada do registo formatada em JSON, para que possa analisar os detalhes pretendidos.

Todos os campos numa entrada de registo, como as indicações de tempo, a gravidade e httpRequest são padrão e estão descritos na documentação de uma entrada de registo.

No entanto, existem algumas etiquetas ou etiquetas de recursos especiais para o Knative serving. Estes estão listados aqui com conteúdos de exemplo:

{
 httpRequest: {}
 insertId:  "5c82b3d1000ece0000000000"
 labels: {
  instanceId:  "00bf4bf00000fb59c906a00000c9e29c2c4e06dce91500000000056008d2b6460f163c0057b97b2345f2725fb2423ee5f0bafd36df887fdb1122371563cf1ff453717282afe000001"
 }
 logName:  "projects/my-project/logs/kubernetes-engine/enterprise/knative-serving/.googleapis.com%2Frequests"
 receiveTimestamp:  "2019-03-08T18:26:25.981686167Z"
 resource: {
  labels: {
   configuration_name:  "myservice"
   location:  "us-central1"
   project_id:  "my-project"
   revision_name:  "myservice-00002"
   service_name:  "myservice"
  }
  type:  "cloud_run_revision"
 }
 severity:  "INFO"
 timestamp:  "2019-03-08T18:26:25.970397Z"
}
Campo Valores e notas
instanceId A instância do contentor que processou o pedido.
logName Identifica o registo, por exemplo, registo de pedidos, erro padrão, saída padrão, etc.
configuration_name O recurso de configuração que criou a revisão que publicou o pedido.
location Identifica a localização da GCP do serviço.
project_id O projeto no qual o serviço está implementado.
revision_name A revisão que publicou o pedido.
service_name O serviço que publicou o pedido.
type cloud_run_revision. O tipo de recurso do Knative Serving.