Skip to content

策略 YAML 指南

Softprobe 测试通过声明式 YAML 策略apiVersion: softprobe.ai/v1)控制录制、回放 Mock 与差异对比。策略按应用(及可选的环境、操作)匹配,按优先级合并,由 sp-boot 在运行时生效。

通过 CLI 管理三种已支持的策略类型:

bash
sp policy recording validate -f recording.yaml --json
sp policy recording apply -f recording.yaml --json
sp policy mock apply -f mock.yaml --json
sp policy compare apply -f compare.yaml --json
Kind控制内容CLI
RecordingPolicy采样、时间窗口、操作包含/排除、序列化跳过、录制时时间 Mocksp policy recording
MockPolicy跳过/强制 Mock、查找容差、跨应用依赖、无 Mock 时的回退sp policy mock
CompareRulePolicy忽略路径、解压、转换、数组匹配、CEL 校验sp policy compare

JSON Schema 位于后端模块 sp-policy-rulessrc/main/resources/schema/)。在 YAML 顶部添加 # yaml-language-server: $schema=... 可在编辑器中获得补全与校验。

文档通用结构

每种策略的外层结构相同:

yaml
apiVersion: softprobe.ai/v1
kind: RecordingPolicy   # 或 MockPolicy / CompareRulePolicy
metadata:
  name: my-app-recording
  priority: 100
  description: "可选说明"
  enabled: true         # 仅 RecordingPolicy / MockPolicy
selector:
  appIds: [my-app-id]
  envTags:
    env: [prod]
spec:
  # 各 kind 专有字段

通用字段

字段类型必填说明
apiVersionstring必须为 softprobe.ai/v1
kindstring上表三种之一
metadata.namestring唯一标识(小写连字符)
metadata.priorityinteger默认 0;数值越大越晚合并,冲突时优先
metadata.descriptionstring自由文本
metadata.enabledboolean仅录制/Mock;默认 true
selector.matchAllboolean匹配所有应用(系统默认在 priority 0 使用)
selector.appIdsstring[]三选一*精确应用 ID
selector.appIdPatternstring三选一*Glob,如 order-*
selector.excludeAppIdsstring[]从匹配结果中排除
selector.envTagsmap标签键 → 允许值列表,如 env: [prod, staging]。与 Agent 上报标签匹配(-Dsp.mocker.tags=env=prod)。合取:声明的每个键都必须满足;省略 = 所有环境
selector.operationNamesstring[]精确操作名。仅录制与 Mock — CompareRulePolicy 的 selector 不允许
selector.operationNamePatternsstring[]Glob,如 /api/order/*仅录制与 Mock

*selector 至少包含 matchAllappIdsappIdPattern 之一。

选择器维度为合取:应用匹配 AND(可选)环境匹配 AND(可选)操作匹配。未约束操作维度时表示「匹配应用下的所有操作」。

合并规则

多条策略匹配同一应用时,按 priority 升序合并(数值大的后应用):

Kind合并行为
Compare标量覆盖;列表/映射合并;同键后者覆盖
Recording标量覆盖;列表合并;timeMock 任一为 true 则 true;serializeSkipclassName + 字段名合并
Mock标量覆盖;skipMock/forceMock 合并;matchTolerancemultiServiceDependencies 按 pattern/应用键后者覆盖

sp-boot 内置 priority 0 的 default-global-*-policy.yaml;用户策略请设置 priority > 0 覆盖。

运行时流水线

text
YAML → 解析 → 校验 → Mongo → 解析合并 → 编译 → PolicyCache(fresh 60s,stale 24h)

Mongo 加载超时时安全降级(录制:不录;Mock:透传)。

编写建议

  1. 在编辑器中启用 JSON Schema 做行内校验。
  2. 应用级策略避免滥用 matchAll: true — 系统默认已提供兜底。
  3. YAML 注释写原因;字段含义以 schema 为准。

RecordingPolicy

录制策略。

控制 Agent 录什么:采样、时段、操作过滤、脱敏元数据、序列化跳过、录制时时间 Mock。

spec 字段

区块字段类型语义
samplingratePerHundredSecondsinteger ≥ 0每 100 秒窗口最多录制请求数;0 = 不录
samplingmachineCountLimitinteger ≥ 1 或省略同环境组内同时录制的实例上限。省略 = 不限。慎用 1(易导致占坑)
timeWindowdaysOfWeekMONSUN*省略整段 = 7×24
timeWindowfrom / toHH:mm必须成对;from 严格早于 to。Agent 使用 JVM 本地时区
operationsexcludestring[]不录制的操作 Glob(黑名单)
operationsincludestring[]非空时为白名单:只录这些;exclude 仍在 include 之后生效
sensitiveDataheadersstring[]头名(见下方说明)
sensitiveDatabodyPathsstring[]JSONPath,必须以 $ 开头
sensitiveDataqueryParamsstring[]查询参数名
sensitiveDataplaceholderstring替换占位符,默认 ***
serializeSkipclassNamestringJava 类名
serializeSkipfieldNamesstring[]跳过的字段
timeMockboolean录制时 Mock java.time.*
extrasmap原样下发到 Agent extendField

录制路径上的 sensitiveData

后端会把 sensitiveData 写入 Agent 线协议,但 Java Agent 尚未在录制时执行脱敏。回放 Mock 键噪声请用 MockPolicy.spec.matchTolerance;查看/查询时脱敏请用 SensitivePolicy(REST,暂无 sp policy CLI)。

修改录制策略的包含/排除列表会影响调度服务构建的回放范围,无需单独改调度文档。

完整示例

yaml
apiVersion: softprobe.ai/v1
kind: RecordingPolicy
metadata:
  name: order-service-prod
  description: "生产录制 — 50 次/100s,工作时间,脱敏元数据"
  priority: 100
  enabled: true
selector:
  appIds: [order-service]
  envTags:
    env: [prod]
  operationNamePatterns:
    - "/api/order/*"
spec:
  sampling:
    ratePerHundredSeconds: 50
    machineCountLimit: 3
  timeWindow:
    daysOfWeek: [MON, TUE, WED, THU, FRI]
    from: "09:00"
    to: "18:00"
  operations:
    exclude:
      - "/health"
      - "/metrics/**"
      - "/actuator/**"
  sensitiveData:
    headers: [authorization, cookie, x-api-key]
    bodyPaths:
      - "$.password"
      - "$.user.phone"
    queryParams: [token, sessionId]
    placeholder: "***"
  serializeSkip:
    - className: com.example.order.domain.Order
      fieldNames: [internalNote]
  timeMock: false
  extras: {}

仅白名单录制示例

yaml
apiVersion: softprobe.ai/v1
kind: RecordingPolicy
metadata:
  name: order-service-whitelist
  priority: 110
selector:
  appIds: [order-service]
spec:
  sampling:
    ratePerHundredSeconds: 100
  operations:
    include:
      - "/api/order/**"
    exclude:
      - "/api/order/internal/**"

MockPolicy

Mock 策略。

控制回放时依赖 Mock:哪些调用用录制数据、哪些走真实下游、Mock 键容差、跨应用依赖、无匹配 Mock 时的行为。

spec 字段

区块字段类型语义
mockByDefaultboolean默认 true:除 skipMock 外全部 Mock;false:除 forceMock 外走真实下游
operationsskipMockstring[]Category:operationGlob — 不 Mock,调真实下游
operationsforceMockstring[]Category:operationGlob — 必须 Mock;优先于 skipMock
matchToleranceoperationPatternstring入口操作 Glob
matchToleranceignoreHeadersstring[]Mock 指纹中忽略的请求头
matchToleranceignoreQueryParamsstring[]忽略的查询参数
matchToleranceignoreBodyPathsstring[]忽略的 body 路径
multiServiceDependenciesdownstreamAppstring下游应用 ID
multiServiceDependenciesoperationsstring[]精确下游操作
multiServiceDependenciesoperationPatternsstring[]Glob(operationsoperationPatterns 至少填一项)
fallbackstrategyenumFAIL(默认)、PASS_THROUGHRETURN_DEFAULT
fallbackdefaultResponseobjectRETURN_DEFAULT 时必填:statusCodecontentTypebodyheaders

skipMock / forceMock 的依赖分类

必须使用 Category:operationGlob — 无前缀的裸 Glob 会被拒绝

Category典型 operationGlob
HttpClient/payment/charge/internal/**
Databaseselect_**
RedisGET user:*
DubboConsumercom.foo.Service#method
SofaConsumerRPC 操作名
DubboStreamProvider流式操作
QMessageProducer主题或消息 ID
ConfigFile配置键
UserDynamiccom.foo.Cache.get(用户配置的动态类)
DynamicClassSystemTime.**RandomSource.**(内置;全局默认强制 Mock,用户 skipMock` 无效)
Encryptioncom.foo.Crypto.encrypt
IbmMQMQ 目的地
SoapClientSOAP 操作
DSRDSR 操作

操作段 Glob:*(单段)、**(多段)、?(单字符)。

分类键是依赖类型

不要在 Mock 规则中使用 ServletDubboProvider入口类型 — 仅上表依赖分类有效。

完整示例

yaml
apiVersion: softprobe.ai/v1
kind: MockPolicy
metadata:
  name: order-service-replay
  description: "order-service 回放默认"
  priority: 100
  enabled: true
selector:
  appIds: [order-service]
  envTags:
    env: [staging, prod]
spec:
  mockByDefault: true
  operations:
    skipMock:
      - "HttpClient:/health"
      - "HttpClient:/internal/admin/**"
    forceMock:
      - "HttpClient:/payment/charge"
      - "Database:*"
  matchTolerance:
    - operationPattern: "/api/order/**"
      ignoreHeaders: [x-request-id, x-trace-id, x-b3-*]
      ignoreQueryParams: [_t, timestamp]
  multiServiceDependencies:
    - downstreamApp: payment-service
      operations: ["/charge", "/refund"]
    - downstreamApp: inventory-service
      operationPatterns: ["/reserve", "/release"]
  fallback:
    strategy: FAIL

透传回退示例

yaml
apiVersion: softprobe.ai/v1
kind: MockPolicy
metadata:
  name: order-service-isolated-replay
  priority: 100
selector:
  appIds: [order-service]
spec:
  fallback:
    strategy: PASS_THROUGH

RETURN_DEFAULT 回退示例

yaml
apiVersion: softprobe.ai/v1
kind: MockPolicy
metadata:
  name: order-service-default-mock
  priority: 100
selector:
  appIds: [order-service]
spec:
  operations:
    forceMock:
      - "HttpClient:/legacy/ping"
  fallback:
    strategy: RETURN_DEFAULT
    defaultResponse:
      statusCode: 200
      contentType: application/json
      body: '{"status":"ok"}'
      headers:
        x-mock: "true"

CompareRulePolicy

对比策略。

控制回放差异对比中的噪声:忽略路径、解压、归一化、数组匹配、对比后 CEL 过滤。

操作范围

不要selector 上写 operationNamesoperationNamePatterns — 保存时会被拒绝。按操作规则请用 spec.operationSpecs[]

spec 字段

区块字段类型语义
defaultstimeToleranceMsinteger ≥ 0CEL 中 time_tolerance_ms 及时间类规则
defaultsignoreHeaderPatternsstring[]对比时跳过的头名 Glob
includePathsstring[]JSON Pointer 白名单;空 = 对比全部
excludePathsstring[]JSON Pointer 黑名单(预过滤)
decompress[]pathstringJSON Pointer 或 Glob
decompress[]codecenumPLAIN_JSONBASE64_JSONGZIP_BASE64_JSON
transforms[]pathstringJSON Pointer
transforms[]expressionstring对比前归一化的 CEL
arrays[]pathstring数组字段路径
arrays[]strategyenumBY_INDEX(默认)或 BY_KEY
arrays[]keysstring[]BY_KEY 时必填
arrays[]references[]objectfieldtargettargetKey
validations[]idstring规则唯一 ID
validations[]namestring显示名
validations[]expressionstringCEL,结果为 bool
validations[]actionenumDROP(丢弃该差异)
validations[]enabledboolean默认 true
validations[]messagestring说明
operationSpecs[]operationNames / operationNamePatternsstring[]覆盖的入口操作
operationSpecs[]specobject与顶层 spec 相同的叶子字段(不可嵌套 operationSpecs

路径为 JSON Pointer/foo/bar)。Glob:* 单段,** 任意深度。

CEL 变量与函数

用于 validationstransforms

名称类型含义
leftstring录制侧值
rightstring回放侧值
pathstringJSON Pointer
pointerstringpath
fieldNamestring叶子字段名
categorystring依赖分类,如 DATABASE
time_tolerance_msint来自 defaults.timeToleranceMs
isTimestamp(s)函数是否为可识别时间戳
toTimestamp(s)函数转为 epoch 毫秒
matches方法字符串正则

按分类忽略差异(如整类 DATABASEbody)通过 CEL validations 实现,无单独「按分类忽略」字段。

完整示例(应用默认 + 按操作覆盖)

yaml
apiVersion: softprobe.ai/v1
kind: CompareRulePolicy
metadata:
  name: order-service-compare
  description: "order-service 对比规则"
  priority: 100
selector:
  appIds: [order-service]
spec:
  defaults:
    timeToleranceMs: 60000
    ignoreHeaderPatterns: [x-request-id, x-b3-*]
  excludePaths:
    - "/response/headers/date"
    - "/response/body/metadata/generatedAt"
  decompress:
    - path: "/response/body/payload"
      codec: GZIP_BASE64_JSON
  arrays:
    - path: "/response/body/items"
      strategy: BY_KEY
      keys: [skuId]
  validations:
    - id: ignore-uuids
      name: 忽略 UUID 对
      expression: >-
        left.matches("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")
        && right.matches("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")
      action: DROP
      enabled: true
      message: 两侧均为 UUID
    - id: ignore-db-body
      name: DATABASE 类忽略 body
      expression: 'category == "DATABASE" && fieldName == "body"'
      action: DROP
      enabled: true
  operationSpecs:
    - operationNamePatterns: ["/api/order/export"]
      spec:
        excludePaths:
          - "/response/body/exportJobId"
        validations:
          - id: export-timestamp-tolerance
            expression: >-
              isTimestamp(left) && isTimestamp(right)
              && math.abs(toTimestamp(left) - toTimestamp(right)) <= time_tolerance_ms
            action: DROP
            enabled: true

动态类

不属于 RecordingPolicy。在动态类配置(控制台或存储 API)中登记方法。回放时分类为 UserDynamic 或内置 DynamicClass(如 SystemTime.*)。用 MockPolicyforceMock / skipMock 控制行为。

回放匹配顺序:先按请求参数精确匹配,再无命中时按方法签名模糊匹配。

SensitivePolicy(敏感数据策略)

第四种策略,用于查询/查看时脱敏(REST API;暂无 sp policy CLI)。与 RecordingPolicy.spec.sensitiveData 分离。

字段说明
spec.fieldNameRules[]pattern(Java 正则)、typeNAMEID_CARDPHONEEMAILPASSPORTDEFAULTNONE
spec.contentRules[]同上,匹配字段
yaml
apiVersion: softprobe.ai/v1
kind: SensitivePolicy
metadata:
  name: order-service-sensitive
  priority: 100
selector:
  appIds: [order-service]
spec:
  fieldNameRules:
    - pattern: "(?i)^password$"
      type: NAME
  contentRules:
    - pattern: "^1[3-9]\\d{9}$"
      type: PHONE

相关文档

零代码改动 · 全上下文可见性 · 成本优化