guidewire-debug-bundle

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Guidewire Debug Bundle

Guidewire调试工具包

Overview

概述

Comprehensive debugging techniques for Guidewire InsuranceSuite including Gosu debugging, Cloud API tracing, log analysis, and performance profiling.
针对Guidewire InsuranceSuite的全面调试技术,包括Gosu调试、Cloud API追踪、日志分析和性能剖析。

Prerequisites

前提条件

  • Access to Guidewire Cloud Console
  • IntelliJ IDEA with Gosu plugin
  • Basic understanding of Java debugging
  • Access to application logs
  • 拥有Guidewire Cloud Console访问权限
  • 安装了Gosu插件的IntelliJ IDEA
  • 具备Java调试基础知识
  • 可访问应用日志

Instructions

操作步骤

Step 1: Enable Debug Logging

步骤1:启用调试日志

xml
<!-- config/logging/log4j2.xml -->
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <RollingFile name="DebugFile" fileName="logs/debug.log"
                 filePattern="logs/debug-%d{yyyy-MM-dd}-%i.log.gz">
      <PatternLayout pattern="%d{ISO8601} [%t] %-5level %logger{36} - %msg%n"/>
      <Policies>
        <SizeBasedTriggeringPolicy size="100 MB"/>
      </Policies>
    </RollingFile>
  </Appenders>

  <Loggers>
    <!-- Application logging -->
    <Logger name="gw.custom" level="DEBUG"/>
    <Logger name="gw.plugin" level="DEBUG"/>

    <!-- API logging -->
    <Logger name="gw.api.rest" level="DEBUG"/>
    <Logger name="gw.api.webservice" level="DEBUG"/>

    <!-- Database query logging -->
    <Logger name="gw.api.database" level="DEBUG"/>
    <Logger name="org.hibernate.SQL" level="DEBUG"/>

    <!-- Integration logging -->
    <Logger name="gw.integration" level="DEBUG"/>

    <Root level="INFO">
      <AppenderRef ref="Console"/>
      <AppenderRef ref="DebugFile"/>
    </Root>
  </Loggers>
</Configuration>
xml
<!-- config/logging/log4j2.xml -->
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <RollingFile name="DebugFile" fileName="logs/debug.log"
                 filePattern="logs/debug-%d{yyyy-MM-dd}-%i.log.gz">
      <PatternLayout pattern="%d{ISO8601} [%t] %-5level %logger{36} - %msg%n"/>
      <Policies>
        <SizeBasedTriggeringPolicy size="100 MB"/>
      </Policies>
    </RollingFile>
  </Appenders>

  <Loggers>
    <!-- Application logging -->
    <Logger name="gw.custom" level="DEBUG"/>
    <Logger name="gw.plugin" level="DEBUG"/>

    <!-- API logging -->
    <Logger name="gw.api.rest" level="DEBUG"/>
    <Logger name="gw.api.webservice" level="DEBUG"/>

    <!-- Database query logging -->
    <Logger name="gw.api.database" level="DEBUG"/>
    <Logger name="org.hibernate.SQL" level="DEBUG"/>

    <!-- Integration logging -->
    <Logger name="gw.integration" level="DEBUG"/>

    <Root level="INFO">
      <AppenderRef ref="Console"/>
      <AppenderRef ref="DebugFile"/>
    </Root>
  </Loggers>
</Configuration>

Step 2: Gosu Debugging in IDE

步骤2:在IDE中进行Gosu调试

gosu
// Add debug breakpoints and logging
package gw.custom.debug

uses gw.api.util.Logger

class DebugHelper {
  private static final var LOG = Logger.forCategory("DebugHelper")

  // Debug method entry/exit
  static function trace<T>(methodName : String, block() : T) : T {
    LOG.debug(">>> Entering ${methodName}")
    var startTime = System.currentTimeMillis()
    try {
      var result = block()
      LOG.debug("<<< Exiting ${methodName} (${System.currentTimeMillis() - startTime}ms)")
      return result
    } catch (e : Exception) {
      LOG.error("!!! Exception in ${methodName}: ${e.Message}", e)
      throw e
    }
  }

  // Dump entity state
  static function dumpEntity(entity : KeyableBean) {
    LOG.debug("=== Entity Dump: ${entity.IntrinsicType.Name} ===")
    LOG.debug("  ID: ${entity.ID}")
    LOG.debug("  PublicID: ${entity.PublicID}")

    entity.IntrinsicType.TypeInfo.Properties
      .where(\p -> !p.Name.startsWith("_"))
      .each(\prop -> {
        try {
          var value = prop.Accessor.getValue(entity)
          LOG.debug("  ${prop.Name}: ${value}")
        } catch (e : Exception) {
          LOG.debug("  ${prop.Name}: <error reading>")
        }
      })
  }

  // Debug query execution
  static function debugQuery<T>(query : Query<T>) : List<T> {
    LOG.debug("Query: ${query.toString()}")
    var startTime = System.currentTimeMillis()
    var results = query.select().toList()
    var elapsed = System.currentTimeMillis() - startTime
    LOG.debug("Query returned ${results.Count} rows in ${elapsed}ms")
    return results
  }
}
gosu
// Add debug breakpoints and logging
package gw.custom.debug

uses gw.api.util.Logger

class DebugHelper {
  private static final var LOG = Logger.forCategory("DebugHelper")

  // Debug method entry/exit
  static function trace<T>(methodName : String, block() : T) : T {
    LOG.debug(">>> Entering ${methodName}")
    var startTime = System.currentTimeMillis()
    try {
      var result = block()
      LOG.debug("<<< Exiting ${methodName} (${System.currentTimeMillis() - startTime}ms)")
      return result
    } catch (e : Exception) {
      LOG.error("!!! Exception in ${methodName}: ${e.Message}", e)
      throw e
    }
  }

  // Dump entity state
  static function dumpEntity(entity : KeyableBean) {
    LOG.debug("=== Entity Dump: ${entity.IntrinsicType.Name} ===")
    LOG.debug("  ID: ${entity.ID}")
    LOG.debug("  PublicID: ${entity.PublicID}")

    entity.IntrinsicType.TypeInfo.Properties
      .where(\p -> !p.Name.startsWith("_"))
      .each(\prop -> {
        try {
          var value = prop.Accessor.getValue(entity)
          LOG.debug("  ${prop.Name}: ${value}")
        } catch (e : Exception) {
          LOG.debug("  ${prop.Name}: <error reading>")
        }
      })
  }

  // Debug query execution
  static function debugQuery<T>(query : Query<T>) : List<T> {
    LOG.debug("Query: ${query.toString()}")
    var startTime = System.currentTimeMillis()
    var results = query.select().toList()
    var elapsed = System.currentTimeMillis() - startTime
    LOG.debug("Query returned ${results.Count} rows in ${elapsed}ms")
    return results
  }
}

Step 3: Remote Debugging Setup

步骤3:远程调试设置

bash
undefined
bash
undefined

Start server with debug port

Start server with debug port

export JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" ./gradlew runServer
export JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" ./gradlew runServer

In IntelliJ: Run > Edit Configurations > Remote JVM Debug

In IntelliJ: Run > Edit Configurations > Remote JVM Debug

Host: localhost

Host: localhost

Port: 5005

Port: 5005

Module classpath: your-project

Module classpath: your-project

undefined
undefined

Step 4: API Request Tracing

步骤4:API请求追踪

typescript
// Add request/response logging
import axios, { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse } from 'axios';

function createDebugClient(): AxiosInstance {
  const client = axios.create({
    baseURL: process.env.POLICYCENTER_URL,
    timeout: 30000
  });

  // Request interceptor
  client.interceptors.request.use((config: InternalAxiosRequestConfig) => {
    const requestId = crypto.randomUUID();
    config.headers['X-Request-ID'] = requestId;

    console.log(`[${requestId}] >>> ${config.method?.toUpperCase()} ${config.url}`);
    if (config.data) {
      console.log(`[${requestId}] Request body:`, JSON.stringify(config.data, null, 2));
    }

    (config as any).metadata = { startTime: Date.now(), requestId };
    return config;
  });

  // Response interceptor
  client.interceptors.response.use(
    (response: AxiosResponse) => {
      const metadata = (response.config as any).metadata;
      const elapsed = Date.now() - metadata.startTime;
      const traceId = response.headers['x-gw-trace-id'];

      console.log(`[${metadata.requestId}] <<< ${response.status} (${elapsed}ms) trace=${traceId}`);
      console.log(`[${metadata.requestId}] Response:`, JSON.stringify(response.data, null, 2));

      return response;
    },
    (error) => {
      const metadata = (error.config as any)?.metadata;
      console.error(`[${metadata?.requestId}] !!! Error:`, error.response?.data || error.message);
      throw error;
    }
  );

  return client;
}
typescript
// Add request/response logging
import axios, { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse } from 'axios';

function createDebugClient(): AxiosInstance {
  const client = axios.create({
    baseURL: process.env.POLICYCENTER_URL,
    timeout: 30000
  });

  // Request interceptor
  client.interceptors.request.use((config: InternalAxiosRequestConfig) => {
    const requestId = crypto.randomUUID();
    config.headers['X-Request-ID'] = requestId;

    console.log(`[${requestId}] >>> ${config.method?.toUpperCase()} ${config.url}`);
    if (config.data) {
      console.log(`[${requestId}] Request body:`, JSON.stringify(config.data, null, 2));
    }

    (config as any).metadata = { startTime: Date.now(), requestId };
    return config;
  });

  // Response interceptor
  client.interceptors.response.use(
    (response: AxiosResponse) => {
      const metadata = (response.config as any).metadata;
      const elapsed = Date.now() - metadata.startTime;
      const traceId = response.headers['x-gw-trace-id'];

      console.log(`[${metadata.requestId}] <<< ${response.status} (${elapsed}ms) trace=${traceId}`);
      console.log(`[${metadata.requestId}] Response:`, JSON.stringify(response.data, null, 2));

      return response;
    },
    (error) => {
      const metadata = (error.config as any)?.metadata;
      console.error(`[${metadata?.requestId}] !!! Error:`, error.response?.data || error.message);
      throw error;
    }
  );

  return client;
}

Step 5: Cloud Console Log Analysis

步骤5:Cloud Console日志分析

bash
undefined
bash
undefined

View real-time logs in Guidewire Cloud Console

View real-time logs in Guidewire Cloud Console

Navigate to: Observability > Logs

Navigate to: Observability > Logs

Common log queries (Lucene syntax)

Common log queries (Lucene syntax)

Find errors for a specific claim

Find errors for a specific claim

claimNumber:"CLM-001234" AND level:ERROR
claimNumber:"CLM-001234" AND level:ERROR

Find slow API calls (>5 seconds)

Find slow API calls (>5 seconds)

message:"API call completed" AND duration:[5000 TO *]
message:"API call completed" AND duration:[5000 TO *]

Find authentication failures

Find authentication failures

category:"Authentication" AND level:WARN
category:"Authentication" AND level:WARN

Find integration errors

Find integration errors

category:"gw.integration*" AND level:ERROR
category:"gw.integration*" AND level:ERROR

Download logs via API

Download logs via API

curl -X GET "https://your-tenant.cloud.guidewire.com/api/v1/logs"
-H "Authorization: Bearer ${TOKEN}"
-d "from=2024-01-15T00:00:00Z"
-d "to=2024-01-15T23:59:59Z"
-d "filter=level:ERROR"
-o error-logs.json
undefined
curl -X GET "https://your-tenant.cloud.guidewire.com/api/v1/logs"
-H "Authorization: Bearer ${TOKEN}"
-d "from=2024-01-15T00:00:00Z"
-d "to=2024-01-15T23:59:59Z"
-d "filter=level:ERROR"
-o error-logs.json
undefined

Step 6: Database Query Analysis

步骤6:数据库查询分析

gosu
// Analyze slow queries
uses gw.api.database.Query
uses gw.api.database.QueryPlanExplainer

class QueryDebugger {

  static function explainQuery<T>(query : Query<T>) : String {
    var explainer = new QueryPlanExplainer(query)
    var plan = explainer.explain()

    LOG.debug("=== Query Execution Plan ===")
    LOG.debug("SQL: ${plan.SQL}")
    LOG.debug("Estimated Rows: ${plan.EstimatedRows}")
    LOG.debug("Index Used: ${plan.IndexUsed}")
    LOG.debug("Scan Type: ${plan.ScanType}")

    if (plan.ScanType == "FULL_TABLE_SCAN" && plan.EstimatedRows > 10000) {
      LOG.warn("WARNING: Full table scan on large table!")
    }

    return plan.toString()
  }

  // Profile query execution
  static function profileQuery<T>(name : String, query : Query<T>) : List<T> {
    var startTime = System.nanoTime()
    var results = query.select().toList()
    var elapsed = (System.nanoTime() - startTime) / 1_000_000.0

    LOG.info("Query '${name}': ${results.Count} rows in ${elapsed}ms")

    if (elapsed > 1000) {
      LOG.warn("Slow query detected: ${name}")
      explainQuery(query)
    }

    return results
  }
}
gosu
// Analyze slow queries
uses gw.api.database.Query
uses gw.api.database.QueryPlanExplainer

class QueryDebugger {

  static function explainQuery<T>(query : Query<T>) : String {
    var explainer = new QueryPlanExplainer(query)
    var plan = explainer.explain()

    LOG.debug("=== Query Execution Plan ===")
    LOG.debug("SQL: ${plan.SQL}")
    LOG.debug("Estimated Rows: ${plan.EstimatedRows}")
    LOG.debug("Index Used: ${plan.IndexUsed}")
    LOG.debug("Scan Type: ${plan.ScanType}")

    if (plan.ScanType == "FULL_TABLE_SCAN" && plan.EstimatedRows > 10000) {
      LOG.warn("WARNING: Full table scan on large table!")
    }

    return plan.toString()
  }

  // Profile query execution
  static function profileQuery<T>(name : String, query : Query<T>) : List<T> {
    var startTime = System.nanoTime()
    var results = query.select().toList()
    var elapsed = (System.nanoTime() - startTime) / 1_000_000.0

    LOG.info("Query '${name}': ${results.Count} rows in ${elapsed}ms")

    if (elapsed > 1000) {
      LOG.warn("Slow query detected: ${name}")
      explainQuery(query)
    }

    return results
  }
}

Step 7: Memory and Thread Analysis

步骤7:内存与线程分析

gosu
// Monitor memory usage
class MemoryDebugger {
  static function logMemoryUsage() {
    var runtime = Runtime.getRuntime()
    var totalMB = runtime.totalMemory() / 1024 / 1024
    var freeMB = runtime.freeMemory() / 1024 / 1024
    var usedMB = totalMB - freeMB
    var maxMB = runtime.maxMemory() / 1024 / 1024

    LOG.info("Memory: used=${usedMB}MB, free=${freeMB}MB, total=${totalMB}MB, max=${maxMB}MB")

    if (usedMB > maxMB * 0.9) {
      LOG.warn("HIGH MEMORY USAGE: ${(usedMB * 100.0 / maxMB) as int}%")
    }
  }

  // Dump thread state
  static function dumpThreads() {
    LOG.info("=== Thread Dump ===")
    Thread.getAllStackTraces().each(\thread, stack -> {
      LOG.info("Thread: ${thread.Name} [${thread.State}]")
      stack.each(\frame -> {
        LOG.info("  at ${frame}")
      })
    })
  }
}
gosu
// Monitor memory usage
class MemoryDebugger {
  static function logMemoryUsage() {
    var runtime = Runtime.getRuntime()
    var totalMB = runtime.totalMemory() / 1024 / 1024
    var freeMB = runtime.freeMemory() / 1024 / 1024
    var usedMB = totalMB - freeMB
    var maxMB = runtime.maxMemory() / 1024 / 1024

    LOG.info("Memory: used=${usedMB}MB, free=${freeMB}MB, total=${totalMB}MB, max=${maxMB}MB")

    if (usedMB > maxMB * 0.9) {
      LOG.warn("HIGH MEMORY USAGE: ${(usedMB * 100.0 / maxMB) as int}%")
    }
  }

  // Dump thread state
  static function dumpThreads() {
    LOG.info("=== Thread Dump ===")
    Thread.getAllStackTraces().each(\thread, stack -> {
      LOG.info("Thread: ${thread.Name} [${thread.State}]")
      stack.each(\frame -> {
        LOG.info("  at ${frame}")
      })
    })
  }
}

Debug Support Bundle

调试支持包

typescript
// Collect diagnostic information
interface DebugBundle {
  timestamp: string;
  environment: string;
  version: string;
  systemInfo: any;
  recentErrors: any[];
  configSnapshot: any;
  performanceMetrics: any;
}

async function collectDebugBundle(): Promise<DebugBundle> {
  const bundle: DebugBundle = {
    timestamp: new Date().toISOString(),
    environment: process.env.NODE_ENV || 'unknown',
    version: process.env.APP_VERSION || 'unknown',
    systemInfo: await getSystemInfo(),
    recentErrors: await getRecentErrors(100),
    configSnapshot: getConfigSnapshot(),
    performanceMetrics: await getPerformanceMetrics()
  };

  // Save to file
  const filename = `debug-bundle-${Date.now()}.json`;
  await fs.writeFile(filename, JSON.stringify(bundle, null, 2));
  console.log(`Debug bundle saved to ${filename}`);

  return bundle;
}

async function getSystemInfo() {
  return {
    nodeVersion: process.version,
    platform: process.platform,
    memoryUsage: process.memoryUsage(),
    uptime: process.uptime(),
    apiEndpoint: process.env.POLICYCENTER_URL
  };
}

async function getRecentErrors(limit: number) {
  // Fetch from logging service or local storage
  return [];
}
typescript
// Collect diagnostic information
interface DebugBundle {
  timestamp: string;
  environment: string;
  version: string;
  systemInfo: any;
  recentErrors: any[];
  configSnapshot: any;
  performanceMetrics: any;
}

async function collectDebugBundle(): Promise<DebugBundle> {
  const bundle: DebugBundle = {
    timestamp: new Date().toISOString(),
    environment: process.env.NODE_ENV || 'unknown',
    version: process.env.APP_VERSION || 'unknown',
    systemInfo: await getSystemInfo(),
    recentErrors: await getRecentErrors(100),
    configSnapshot: getConfigSnapshot(),
    performanceMetrics: await getPerformanceMetrics()
  };

  // Save to file
  const filename = `debug-bundle-${Date.now()}.json`;
  await fs.writeFile(filename, JSON.stringify(bundle, null, 2));
  console.log(`Debug bundle saved to ${filename}`);

  return bundle;
}

async function getSystemInfo() {
  return {
    nodeVersion: process.version,
    platform: process.platform,
    memoryUsage: process.memoryUsage(),
    uptime: process.uptime(),
    apiEndpoint: process.env.POLICYCENTER_URL
  };
}

async function getRecentErrors(limit: number) {
  // Fetch from logging service or local storage
  return [];
}

Common Debug Scenarios

常见调试场景

Debugging Workflow Failures

调试工作流故障

gosu
// Add workflow debug hooks
class WorkflowDebugger {
  static function debugWorkflowStep(workflow : Workflow, step : WorkflowStep) {
    LOG.debug("=== Workflow Step Debug ===")
    LOG.debug("Workflow: ${workflow.Name}")
    LOG.debug("Step: ${step.Name}")
    LOG.debug("Status: ${step.Status}")

    // Check preconditions
    step.Preconditions.each(\precond -> {
      var result = precond.evaluate(workflow.Context)
      LOG.debug("Precondition '${precond.Name}': ${result}")
    })

    // Check available actions
    step.AvailableActions.each(\action -> {
      LOG.debug("Available action: ${action.Name}")
    })
  }
}
gosu
// Add workflow debug hooks
class WorkflowDebugger {
  static function debugWorkflowStep(workflow : Workflow, step : WorkflowStep) {
    LOG.debug("=== Workflow Step Debug ===")
    LOG.debug("Workflow: ${workflow.Name}")
    LOG.debug("Step: ${step.Name}")
    LOG.debug("Status: ${step.Status}")

    // Check preconditions
    step.Preconditions.each(\precond -> {
      var result = precond.evaluate(workflow.Context)
      LOG.debug("Precondition '${precond.Name}': ${result}")
    })

    // Check available actions
    step.AvailableActions.each(\action -> {
      LOG.debug("Available action: ${action.Name}")
    })
  }
}

Debugging Integration Failures

调试集成故障

gosu
// Integration debug helper
class IntegrationDebugger {
  static function debugRequest(request : RestRequest) {
    LOG.debug("=== Outbound Request ===")
    LOG.debug("URL: ${request.URL}")
    LOG.debug("Method: ${request.Method}")
    LOG.debug("Headers:")
    request.Headers.each(\name, value -> {
      // Mask sensitive headers
      var displayValue = name.toLowerCase().contains("auth") ? "***" : value
      LOG.debug("  ${name}: ${displayValue}")
    })
    LOG.debug("Body: ${request.Body}")
  }

  static function debugResponse(response : RestResponse) {
    LOG.debug("=== Inbound Response ===")
    LOG.debug("Status: ${response.StatusCode}")
    LOG.debug("Headers:")
    response.Headers.each(\name, value -> {
      LOG.debug("  ${name}: ${value}")
    })
    LOG.debug("Body: ${response.Body}")
  }
}
gosu
// Integration debug helper
class IntegrationDebugger {
  static function debugRequest(request : RestRequest) {
    LOG.debug("=== Outbound Request ===")
    LOG.debug("URL: ${request.URL}")
    LOG.debug("Method: ${request.Method}")
    LOG.debug("Headers:")
    request.Headers.each(\name, value -> {
      // Mask sensitive headers
      var displayValue = name.toLowerCase().contains("auth") ? "***" : value
      LOG.debug("  ${name}: ${displayValue}")
    })
    LOG.debug("Body: ${request.Body}")
  }

  static function debugResponse(response : RestResponse) {
    LOG.debug("=== Inbound Response ===")
    LOG.debug("Status: ${response.StatusCode}")
    LOG.debug("Headers:")
    response.Headers.each(\name, value -> {
      LOG.debug("  ${name}: ${value}")
    })
    LOG.debug("Body: ${response.Body}")
  }
}

Output

输出结果

  • Debug logs with trace information
  • Query execution plans
  • Memory and thread dumps
  • Complete debug bundle for support
  • 包含追踪信息的调试日志
  • 查询执行计划
  • 内存与线程转储
  • 用于支持的完整调试包

Resources

参考资源

Next Steps

后续步骤

For rate limiting information, see
guidewire-rate-limits
.
如需了解速率限制相关信息,请查看
guidewire-rate-limits