You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Stackdriver日志Severity字段在Cloud Run与Compute Engine(Ops Agent)中的兼容性问题及解决方案咨询

Answer

Yes, this is expected behavior, and it boils down to how each environment ingests and processes logs:

  • Cloud Run integrates natively with Google Cloud Logging. When you write structured logs to stdout/stderr, Cloud Run parses them as full LogEntry objects automatically. That’s why using the plain severity field works here—it maps directly to the LogEntry field defined in the Logging API.
  • Compute Engine with Ops Agent operates differently: the agent collects log files, parses JSON content into the jsonPayload field of a LogEntry, and requires explicit mapping for special fields like severity. Without the logging.googleapis.com/severity key, the agent treats severity as just another payload attribute instead of elevating it to the top-level log entry severity.

You don’t need to maintain two separate logging packages—here are two clean solutions to support both environments with a single implementation:


Option 1: Dynamically adjust the severity field name at serialization

You can override the JSON serialization of your Entry struct to use the correct field name based on the runtime environment. Cloud Run automatically sets the K_SERVICE environment variable, so we can use that to detect the environment.

First, modify your Entry struct to skip default serialization for the Severity field, then implement a custom MarshalJSON method:

package yourlogger

import (
    "encoding/json"
    "os"
)

type Severity string

const (
    SeverityInfo  Severity = "INFO"
    SeverityError Severity = "ERROR"
    // Add other severity levels as needed
)

type Entry struct {
    Message   string   `json:"message"`
    Severity  Severity `json:"-"` // Exclude from default JSON serialization
    Trace     string   `json:"logging.googleapis.com/trace,omitempty"`
    Component string   `json:"component,omitempty"`
}

func (e Entry) MarshalJSON() ([]byte, error) {
    payload := make(map[string]interface{})
    payload["message"] = e.Message
    payload["component"] = e.Component
    
    if e.Trace != "" {
        payload["logging.googleapis.com/trace"] = e.Trace
    }

    // Detect if we're running in Cloud Run
    isCloudRun := os.Getenv("K_SERVICE") != ""
    if isCloudRun {
        payload["severity"] = string(e.Severity)
    } else {
        payload["logging.googleapis.com/severity"] = string(e.Severity)
    }

    return json.Marshal(payload)
}

Then update your Log function to serialize the entry properly before logging:

func Log(ctx context.Context, severity Severity, format string, a ...interface{}) {
    entry := Entry{
        Severity:  severity,
        Message:   fmt.Sprintf(format, a...),
        Component: "arbitrary-property",
        Trace:     GetTraceId(ctx),
    }

    logJSON, err := json.Marshal(entry)
    if err != nil {
        // Fallback to plain text logging if serialization fails
        log.Printf("Failed to serialize log entry: %v | Message: %s", err, fmt.Sprintf(format, a...))
        return
    }

    log.Println(string(logJSON))
}

This way, the same logger outputs the correct severity field name whether it’s running in Cloud Run or Compute Engine.


Option 2: Configure Ops Agent to map the plain severity field

If you prefer not to modify your code, update the Ops Agent configuration on your Compute Engine instances to extract severity from the jsonPayload.severity field and elevate it to the top-level log entry severity.

Here’s an example configuration snippet (typically stored at /etc/google-cloud-ops-agent/config.yaml):

logging:
  receivers:
    your-app-receiver:
      type: files
      include_paths:
        - /var/log/your-app/*.log # Update to your app's log path
      json_field: jsonPayload
      severity:
        field: jsonPayload.severity
        default: INFO # Fallback severity if the field is missing
  processors:
    parse-json:
      type: parse_json
      field: message
      output_field: jsonPayload
  service:
    pipelines:
      default_pipeline:
        receivers: [your-app-receiver]
        processors: [parse-json]

After updating the config, restart the Ops Agent:

sudo systemctl restart google-cloud-ops-agent

With this setup, the Ops Agent recognizes the plain severity field in your log entries, matching how Cloud Run processes logs—so you can keep your existing logger implementation unchanged.


Both options work well—choose the one that fits your workflow:

  • Option 1 is code-centric and requires no infrastructure changes.
  • Option 2 keeps your code clean but requires updating Ops Agent configurations across all your Compute Engine instances.

内容的提问来源于stack exchange,提问作者Avishay28

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 20:57:48