yumeng 6 dni temu
rodzic
commit
17abc1b6de

+ 9 - 1
src/main/java/com/adx/tencent/baidu/AdxClient.java

@@ -2,6 +2,8 @@ package com.adx.tencent.baidu;
 
 import com.adx.tencent.baidu.model.*;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.net.URI;
@@ -19,6 +21,8 @@ import java.util.List;
  */
 public class AdxClient {
 
+    private static final Logger log = LoggerFactory.getLogger(AdxClient.class);
+
     public static final String AUCTION_PRICE_MACRO = "${AUCTION_PRICE}";
     public static final String BAIDU_USER_AGENT = "QTech-MeasurementNode/1.2 (Postback; Attribution; S2S)";
 
@@ -38,7 +42,7 @@ public class AdxClient {
      * 向百度 ADX 发起竞价请求,返回归一化后的 BidResponse。
      * 如果百度返回空响应体(无广告填充),返回 null。
      */
-    public NormalizedBidResponse requestBid(Object body) throws IOException, InterruptedException {
+    public NormalizedBidResponse requestBid(String traceId, Object body) throws IOException, InterruptedException {
         if (endpoint == null || endpoint.isBlank()) {
             throw new IllegalStateException("Baidu ADX endpoint is required");
         }
@@ -59,9 +63,13 @@ public class AdxClient {
         // 百度 ADX 无广告填充时可能返回空 body
         byte[] respBody = response.body();
         if (respBody == null || respBody.length == 0) {
+            log.info("[百度ADX][原始响应] traceId={} status={} body=<empty>", traceId, response.statusCode());
             return null;
         }
 
+        String rawBody = new String(respBody, StandardCharsets.UTF_8);
+        log.info("[百度ADX][原始响应] traceId={} status={} body={}", traceId, response.statusCode(), rawBody);
+
         BidResponse bidResponse = objectMapper.readValue(respBody, BidResponse.class);
         return NormalizedBidResponse.from(bidResponse);
     }

+ 12 - 4
src/main/java/com/adx/tencent/honor/HonorClient.java

@@ -50,6 +50,8 @@ public class HonorClient {
         record.setCallbackUrl(callbackUrl);
         record.setRequestBody(toJson(params));
         record.setEventTimeMs(Long.parseLong(params.get("conversionTime")));
+        log.info("[Honor] callback请求: qk={}, tagId={}, conversionId={}, url={}, params={}",
+                payment.getQk(), bid.getTagId(), conversionId, callbackUrl, params);
 
         try {
             HttpRequest request = HttpRequest.newBuilder()
@@ -65,13 +67,13 @@ public class HonorClient {
             if (!record.isOk()) {
                 record.setErrorMessage("HTTP status: " + response.statusCode());
             }
-            log.info("[Honor] callback结果: qk={}, tagId={}, conversionId={}, status={}, ok={}, response={}",
-                    payment.getQk(), bid.getTagId(), conversionId, response.statusCode(), record.isOk(), body);
+            log.info("[Honor] callback结果: qk={}, tagId={}, conversionId={}, url={}, status={}, ok={}, response={}",
+                    payment.getQk(), bid.getTagId(), conversionId, callbackUrl, response.statusCode(), record.isOk(), body);
         } catch (Exception e) {
             record.setOk(false);
             record.setErrorMessage(e.getMessage());
-            log.warn("[Honor] callback失败: qk={}, tagId={}, conversionId={}, error={}",
-                    payment.getQk(), bid.getTagId(), conversionId, e.getMessage());
+            log.warn("[Honor] callback失败: qk={}, tagId={}, conversionId={}, url={}, params={}, error={}",
+                    payment.getQk(), bid.getTagId(), conversionId, callbackUrl, params, e.getMessage());
         }
         return record;
     }
@@ -80,6 +82,9 @@ public class HonorClient {
         HonorMediaCallbackRecord retry = copy(original);
         retry.setAttempt(original.getAttempt() + 1);
         retry.setCreatedAt(Instant.now());
+        log.info("[Honor] callback重试请求: qk={}, tagId={}, eventType={}, attempt={}, url={}, requestBody={}",
+                original.getQk(), original.getTagId(), original.getEventType(), retry.getAttempt(),
+                original.getCallbackUrl(), original.getRequestBody());
         HttpRequest request = HttpRequest.newBuilder()
                 .uri(URI.create(original.getCallbackUrl()))
                 .GET()
@@ -90,6 +95,9 @@ public class HonorClient {
         retry.setResponseBody(new String(response.body(), StandardCharsets.UTF_8));
         retry.setOk(response.statusCode() >= 200 && response.statusCode() < 300);
         if (!retry.isOk()) retry.setErrorMessage("HTTP status: " + response.statusCode());
+        log.info("[Honor] callback重试结果: qk={}, tagId={}, eventType={}, attempt={}, url={}, status={}, ok={}, response={}",
+                retry.getQk(), retry.getTagId(), retry.getEventType(), retry.getAttempt(),
+                retry.getCallbackUrl(), retry.getStatus(), retry.isOk(), retry.getResponseBody());
         return retry;
     }
 

+ 3 - 1
src/main/java/com/adx/tencent/honor/HonorColdStore.java

@@ -46,7 +46,7 @@ public class HonorColdStore {
                     creative_id VARCHAR(128),
                     imp_id VARCHAR(128),
                     tag_id VARCHAR(128) NOT NULL,
-                    price BIGINT UNSIGNED,
+                    price BIGINT UNSIGNED NOT NULL DEFAULT 0,
                     show_urls JSON,
                     click_urls JSON,
                     landing_page TEXT,
@@ -110,6 +110,8 @@ public class HonorColdStore {
             for (String ddl : ddls) {
                 stmt.execute(ddl);
             }
+            stmt.execute("UPDATE honor_ad_bid_events SET price = 0 WHERE price IS NULL");
+            stmt.execute("ALTER TABLE honor_ad_bid_events MODIFY COLUMN price BIGINT UNSIGNED NOT NULL DEFAULT 0");
             stmt.close();
         } catch (Exception e) {
             throw new RuntimeException("honor migrate failed", e);

+ 36 - 22
src/main/java/com/adx/tencent/honor/HonorTrackingController.java

@@ -5,6 +5,7 @@ import com.adx.tencent.baidu.model.NormalizedBidResponse;
 import com.adx.tencent.baidu.model.TrackingResult;
 import com.adx.tencent.honor.model.HonorBidRecord;
 import com.adx.tencent.honor.model.HonorTrackingRecord;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import org.slf4j.Logger;
@@ -38,13 +39,16 @@ public class HonorTrackingController {
     private final AdxClient adxClient;
     private final HonorHotStore hotStore;
     private final HonorPlacement placement;
+    private final ObjectMapper objectMapper;
 
     public HonorTrackingController(AdxClient adxClient,
                                    HonorHotStore hotStore,
-                                   @Nullable HonorPlacement placement) {
+                                   @Nullable HonorPlacement placement,
+                                   ObjectMapper objectMapper) {
         this.adxClient = adxClient;
         this.hotStore = hotStore;
         this.placement = placement;
+        this.objectMapper = objectMapper;
     }
 
     @GetMapping("/honor/impression")
@@ -76,27 +80,29 @@ public class HonorTrackingController {
             log.warn("[荣耀][曝光] 缺少 traceId, params={}", params.keySet());
             throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "missing honor trace id (trackId)");
         }
-        log.info("[荣耀][曝光] 收到曝光请求 | traceId={} | IP={} | 全部入参: {}", traceId, clientIp(request), params);
+        log.info("[荣耀][曝光][入参] traceId={} ip={} params={}", traceId, clientIp(request), params);
+
+        NormalizedBidResponse response = adxClient.requestBid(traceId, buildBidRequest(request, traceId, params));
 
-        NormalizedBidResponse response = adxClient.requestBid(buildBidRequest(request, traceId, params));
         if (response == null) {
-            log.warn("[荣耀][曝光] 百度ADX返回空响应, traceId={}", traceId);
+            log.warn("[荣耀][曝光][百度结果] traceId={} empty=true", traceId);
             throw new ResponseStatusException(HttpStatus.BAD_GATEWAY, "empty baidu ADX response");
         }
-        log.info("[荣耀][曝光] 百度ADX返回: qk={}, hasBid={}, showUrls={}, clickUrls={}",
+        log.info("[荣耀][曝光][竞价结果] traceId={} qk={} bidId={} success={} price={} clickUrlCount={} showUrlCount={}",
+                traceId,
                 response.getQk(),
+                response.getBidId(),
                 response.getBid() != null,
-                response.getBid() != null && response.getBid().getShowUrls() != null ? response.getBid().getShowUrls().size() : 0,
-                response.getBid() != null && response.getBid().getClickUrls() != null ? response.getBid().getClickUrls().size() : 0);
+                response.getBid() != null ? response.getBid().getPrice() : 0,
+                response.getBid() != null && response.getBid().getClickUrls() != null ? response.getBid().getClickUrls().size() : 0,
+                response.getBid() != null && response.getBid().getShowUrls() != null ? response.getBid().getShowUrls().size() : 0);
 
         HonorBidRecord record = bidRecordFromResponse(response, traceId, "impression", params);
         hotStore.recordBid(record);
-        log.info("[荣耀][曝光] 已缓存bid, qk={}, traceId={}", record.getQk(), traceId);
 
         List<TrackingResult> tracking = Collections.emptyList();
         if (response.getBid() != null && response.getBid().getShowUrls() != null && !response.getBid().getShowUrls().isEmpty()) {
             tracking = adxClient.reportImpression(response.getBid().getShowUrls(), response.getBid().getPrice());
-            log.info("[荣耀][曝光] 曝光上报完成, qk={}, results={}", record.getQk(), tracking);
             recordTracking(record.getQk(), tagId, "impression", tracking);
         }
         return Map.of("qk", record.getQk(), "traceId", traceId, "tagId", tagId);
@@ -111,43 +117,43 @@ public class HonorTrackingController {
             log.warn("[荣耀][点击] 缺少 traceId, params={}", params.keySet());
             throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "missing honor trace id (trackId)");
         }
-        log.info("[荣耀][点击] 收到点击请求 | traceId={} | IP={} | 全部入参: {}", traceId, clientIp(request), params);
+        log.info("[荣耀][点击][入参] traceId={} ip={} params={}", traceId, clientIp(request), params);
 
         HonorBidRecord record = hotStore.findBidByMediaTrace(traceId);
         if (record == null) {
-            log.info("[荣耀][点击] Redis未命中, 发起竞价请求, traceId={}", traceId);
-            NormalizedBidResponse bidResponse = adxClient.requestBid(buildBidRequest(request, traceId, params));
+            NormalizedBidResponse bidResponse = adxClient.requestBid(traceId, buildBidRequest(request, traceId, params));
             if (bidResponse == null) {
-                log.warn("[荣耀][点击] 百度ADX返回空响应, traceId={}", traceId);
+                log.warn("[荣耀][点击][百度结果] traceId={} empty=true", traceId);
                 throw new ResponseStatusException(HttpStatus.BAD_GATEWAY, "empty baidu ADX response");
             }
+            log.info("[荣耀][点击][竞价结果] traceId={} qk={} bidId={} success={} price={} clickUrlCount={} showUrlCount={}",
+                    traceId,
+                    bidResponse.getQk(),
+                    bidResponse.getBidId(),
+                    bidResponse.getBid() != null,
+                    bidResponse.getBid() != null ? bidResponse.getBid().getPrice() : 0,
+                    bidResponse.getBid() != null && bidResponse.getBid().getClickUrls() != null ? bidResponse.getBid().getClickUrls().size() : 0,
+                    bidResponse.getBid() != null && bidResponse.getBid().getShowUrls() != null ? bidResponse.getBid().getShowUrls().size() : 0);
             record = bidRecordFromResponse(bidResponse, traceId, "click", params);
             hotStore.recordBid(record);
-            log.info("[荣耀][点击] 竞价成功, qk={}, traceId={}", record.getQk(), traceId);
             if (bidResponse.getBid() != null && bidResponse.getBid().getShowUrls() != null && !bidResponse.getBid().getShowUrls().isEmpty()) {
                 List<TrackingResult> impressionTracking = adxClient.reportImpression(
                         bidResponse.getBid().getShowUrls(), bidResponse.getBid().getPrice());
-                log.info("[荣耀][点击] Redis未命中补竞价后,曝光上报完成, qk={}, results={}", record.getQk(), impressionTracking);
                 recordTracking(record.getQk(), tagId, "impression", impressionTracking);
             }
-        } else {
-            log.info("[荣耀][点击] Redis命中, qk={}, traceId={}", record.getQk(), traceId);
         }
 
         List<TrackingResult> tracking = adxClient.reportClick(
                 record.getClickUrls() != null ? record.getClickUrls() : Collections.emptyList());
-        log.info("[荣耀][点击] 点击上报完成, qk={}, results={}", record.getQk(), tracking);
         recordTracking(record.getQk(), tagId, "click", tracking);
         try {
             hotStore.shrinkAfterClick(record);
         } catch (Exception e) {
-            log.warn("[荣耀][点击] Redis缩减失败(不影响主流程), qk={}, error={}", record.getQk(), e.getMessage());
         }
 
         String destination = record.getAppStoreLink() != null && !record.getAppStoreLink().isBlank()
                 ? record.getAppStoreLink() : record.getLandingPage();
         if (destination != null && !destination.isBlank()) {
-            log.info("[荣耀][点击] 302重定向, qk={}, destination={}", record.getQk(), destination);
             response.sendRedirect(destination);
             return null;
         }
@@ -214,7 +220,7 @@ public class HonorTrackingController {
         bidReq.put("device", device);
         List<Integer> appList = parseAppList(firstParam(params, "appList", "app_list", "applist"));
         if (!appList.isEmpty()) bidReq.put("appList", appList);
-        log.info("[荣耀][百度ADX] 竞价请求 | traceId={} | body={}", traceId, bidReq);
+        log.info("[荣耀][百度请求] traceId={} body={}", traceId, toJson(bidReq));
         return bidReq;
     }
 
@@ -316,7 +322,7 @@ public class HonorTrackingController {
             try {
                 result.add(Integer.parseInt(item));
             } catch (NumberFormatException e) {
-                log.warn("[荣耀][百度ADX] 忽略非法 appList 值 | raw={} | item={}", value, item);
+                log.warn("[荣耀][百度请求] invalidAppList raw={} item={}", value, item);
             }
         }
         return result;
@@ -380,4 +386,12 @@ public class HonorTrackingController {
         if (xri != null && !xri.isBlank()) return xri.trim();
         return request.getRemoteAddr();
     }
+
+    private String toJson(Object value) {
+        try {
+            return objectMapper.writeValueAsString(value);
+        } catch (Exception e) {
+            return String.valueOf(value);
+        }
+    }
 }

+ 2 - 2
src/main/java/com/adx/tencent/honor/model/HonorBidRecord.java

@@ -52,7 +52,7 @@ public class HonorBidRecord {
     public String getTagId() { return tagId; }
     public void setTagId(String v) { this.tagId = v; }
     public Long getPrice() { return price; }
-    public void setPrice(Long v) { this.price = v; }
+    public void setPrice(Long v) { this.price = v == null ? 0L : v; }
     public List<String> getShowUrls() { return showUrls; }
     public void setShowUrls(List<String> v) { this.showUrls = v; }
     public List<String> getClickUrls() { return clickUrls; }
@@ -107,7 +107,7 @@ public class HonorBidRecord {
         cold.accountId = this.accountId;
         cold.eventType = this.eventType;
         cold.tagId = this.tagId;
-        cold.price = this.price;
+        cold.price = this.price == null ? 0L : this.price;
         cold.packageName = this.packageName;
         cold.mediaParams = slimDeviceParams(this.mediaParams);
         cold.createdAt = this.createdAt;

+ 34 - 25
src/main/java/com/adx/tencent/httpapi/TrackingController.java

@@ -6,6 +6,7 @@ import com.adx.tencent.baidu.model.TrackingResult;
 import com.adx.tencent.storage.RedisHotStore;
 import com.adx.tencent.storage.model.BidRecord;
 import com.adx.tencent.storage.model.TrackingRecord;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
@@ -36,14 +37,17 @@ public class TrackingController {
     private final RedisHotStore hotStore;
     private final MediaPlacement tencentPlacement;
     private final boolean allowIpOverride;
+    private final ObjectMapper objectMapper;
 
     public TrackingController(AdxClient adxClient,
                               RedisHotStore hotStore,
                               @Nullable MediaPlacement tencentPlacement,
+                              ObjectMapper objectMapper,
                               @Value("${spring.profiles.active:}") String activeProfile) {
         this.adxClient = adxClient;
         this.hotStore = hotStore;
         this.tencentPlacement = tencentPlacement;
+        this.objectMapper = objectMapper;
         this.allowIpOverride = "dev".equals(activeProfile) || "test".equals(activeProfile);
     }
 
@@ -82,31 +86,32 @@ public class TrackingController {
             throw new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE, "tencent placement not configured");
         }
 
-        log.info("[腾讯][曝光] 收到曝光请求 | traceId={} | IP={} | 全部入参: {}", traceId, clientIp(request), params);
+        log.info("[腾讯][曝光][入参] traceId={} ip={} params={}", traceId, clientIp(request), params);
 
         Map<String, Object> bidRequest = mediaBidRequest(request, "tencent", traceId, params, tencentPlacement);
-        NormalizedBidResponse response = adxClient.requestBid(bidRequest);
+        NormalizedBidResponse response = adxClient.requestBid(traceId, bidRequest);
         if (response == null) {
-            log.warn("[腾讯][曝光] 百度ADX返回空响应, traceId={}", traceId);
+            log.warn("[腾讯][曝光][百度结果] traceId={} empty=true", traceId);
             throw new ResponseStatusException(HttpStatus.BAD_GATEWAY, "empty baidu ADX response");
         }
 
-        log.info("[腾讯][曝光] 百度ADX返回: qk={}, hasBid={}, showUrls={}, clickUrls={}",
+        log.info("[腾讯][曝光][竞价结果] traceId={} qk={} bidId={} success={} price={} clickUrlCount={} showUrlCount={}",
+                traceId,
                 response.getQk(),
+                response.getBidId(),
                 response.getBid() != null,
-                response.getBid() != null && response.getBid().getShowUrls() != null ? response.getBid().getShowUrls().size() : 0,
-                response.getBid() != null && response.getBid().getClickUrls() != null ? response.getBid().getClickUrls().size() : 0);
+                response.getBid() != null ? response.getBid().getPrice() : 0,
+                response.getBid() != null && response.getBid().getClickUrls() != null ? response.getBid().getClickUrls().size() : 0,
+                response.getBid() != null && response.getBid().getShowUrls() != null ? response.getBid().getShowUrls().size() : 0);
 
         BidRecord record = bidRecordFromMediaResponse(response, "tencent", traceId, "impression", params);
         hotStore.recordBid(record);
-        log.info("[腾讯][曝光] 已缓存bid, qk={}, traceId={}", record.getQk(), traceId);
 
         // 上报百度曝光
         if (response.getBid() != null && response.getBid().getShowUrls() != null
                 && !response.getBid().getShowUrls().isEmpty()) {
             List<TrackingResult> trackingResults = adxClient.reportImpression(
                     response.getBid().getShowUrls(), response.getBid().getPrice());
-            log.info("[腾讯][曝光] 曝光上报完成, qk={}, results={}", response.getQk(), trackingResults);
             recordTrackingResults(response.getQk(), "impression", trackingResults);
         }
         return Map.of("qk", nvl(record.getQk()), "traceId", traceId);
@@ -143,19 +148,25 @@ public class TrackingController {
             throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "missing media trace id (click_id/oaid/imei/idfa)");
         }
 
-        log.info("[腾讯][点击] 收到点击请求 | traceId={} | IP={} | 全部入参: {}", traceId, clientIp(request), params);
+        log.info("[腾讯][点击][入参] traceId={} ip={} params={}", traceId, clientIp(request), params);
 
-        // 先从 Redis 按 mediaTrace 查找已有 bid
         BidRecord record = hotStore.findBidByMediaTrace("tencent", traceId);
         if (record == null) {
-            log.info("[腾讯][点击] Redis未命中, 发起竞价请求, traceId={}", traceId);
             // 未找到,临时发起竞价请求
             Map<String, Object> bidRequest = mediaBidRequest(request, "tencent", traceId, params, tencentPlacement);
-            NormalizedBidResponse resp = adxClient.requestBid(bidRequest);
+            NormalizedBidResponse resp = adxClient.requestBid(traceId, bidRequest);
             if (resp == null) {
-                log.warn("[腾讯][点击] 百度ADX返回空响应, traceId={}", traceId);
+                log.warn("[腾讯][点击][百度结果] traceId={} empty=true", traceId);
                 throw new ResponseStatusException(HttpStatus.BAD_GATEWAY, "empty baidu ADX response");
             }
+            log.info("[腾讯][点击][竞价结果] traceId={} qk={} bidId={} success={} price={} clickUrlCount={} showUrlCount={}",
+                    traceId,
+                    resp.getQk(),
+                    resp.getBidId(),
+                    resp.getBid() != null,
+                    resp.getBid() != null ? resp.getBid().getPrice() : 0,
+                    resp.getBid() != null && resp.getBid().getClickUrls() != null ? resp.getBid().getClickUrls().size() : 0,
+                    resp.getBid() != null && resp.getBid().getShowUrls() != null ? resp.getBid().getShowUrls().size() : 0);
             BidRecord newRecord = bidRecordFromMediaResponse(resp, "tencent", traceId, "click", params);
             hotStore.recordBid(newRecord);
             record = newRecord;
@@ -163,32 +174,22 @@ public class TrackingController {
                     && !resp.getBid().getShowUrls().isEmpty()) {
                 List<TrackingResult> impressionResults = adxClient.reportImpression(
                         resp.getBid().getShowUrls(), resp.getBid().getPrice());
-                log.info("[腾讯][点击] Redis未命中补竞价后,曝光上报完成, qk={}, results={}", record.getQk(), impressionResults);
                 recordTrackingResults(record.getQk(), "impression", impressionResults);
             }
-            log.info("[腾讯][点击] 竞价成功, qk={}, traceId={}", record.getQk(), traceId);
-        } else {
-            log.info("[腾讯][点击] Redis命中, qk={}, traceId={}", record.getQk(), traceId);
         }
 
-        // 上报百度点击
         List<TrackingResult> trackingResults = adxClient.reportClick(
                 record.getClickUrls() != null ? record.getClickUrls() : Collections.emptyList());
-        log.info("[腾讯][点击] 点击上报完成, qk={}, results={}", record.getQk(), trackingResults);
         recordTrackingResults(record.getQk(), "click", trackingResults);
 
-        // 点击处理完成,缩减 Redis 数据(清除 clickUrls/landingPage/appStoreLink)
         String destination = record.getAppStoreLink() != null && !record.getAppStoreLink().isBlank()
                 ? record.getAppStoreLink() : record.getLandingPage();
         try {
             hotStore.shrinkAfterClick(record);
         } catch (Exception e) {
-            log.warn("[腾讯][点击] Redis缩减失败(不影响主流程), qk={}, error={}", record.getQk(), e.getMessage());
         }
 
-        // 重定向到 landing page 或 app store link
         if (destination != null && !destination.isBlank()) {
-            log.info("[腾讯][点击] 302重定向, qk={}, destination={}", record.getQk(), destination);
             response.sendRedirect(destination);
             return null;
         }
@@ -298,7 +299,7 @@ public class TrackingController {
         List<Integer> appList = parseAppList(firstParam(params, "appList", "app_list", "applist"));
         if (!appList.isEmpty()) bidReq.put("appList", appList);
 
-        log.info("[腾讯][百度ADX] 竞价请求 | traceId={} | body={}", traceId, bidReq);
+        log.info("[腾讯][百度请求] traceId={} body={}", traceId, toJson(bidReq));
 
         return bidReq;
     }
@@ -373,7 +374,7 @@ public class TrackingController {
             try {
                 result.add(Integer.parseInt(item));
             } catch (NumberFormatException e) {
-                log.warn("[腾讯][百度ADX] 忽略非法 appList 值 | raw={} | item={}", value, item);
+                log.warn("[腾讯][百度请求] invalidAppList raw={} item={}", value, item);
             }
         }
         return result;
@@ -409,4 +410,12 @@ public class TrackingController {
     }
 
     private static String nvl(String s) { return s != null ? s : ""; }
+
+    private String toJson(Object value) {
+        try {
+            return objectMapper.writeValueAsString(value);
+        } catch (Exception e) {
+            return String.valueOf(value);
+        }
+    }
 }

+ 5 - 5
src/main/resources/application-dev.yml

@@ -63,20 +63,20 @@ adx:
   tidb-keepalive-time: 2m
 
   # --- Task ---
-  skip-leader-election: true
+  skip-leader-election: false
 
   # --- Conversion Sync ---
-  conversion-sync-enabled: true
+  conversion-sync-enabled: false
   conversion-sync-interval: 30s
 
   # --- Callback Retry ---
-  callback-retry-enabled: true
+  callback-retry-enabled: false
 
   # --- Tag Event Sync(广告位回传方式 -> Redis)---
-  tag-event-sync-enabled: true
+  tag-event-sync-enabled: false
   tag-event-sync-interval: 300s
 
   # --- Honor Tag Event Sync(荣耀广告位回传方式 -> Redis)---
-  honor-tag-event-sync-enabled: true
+  honor-tag-event-sync-enabled: false
   honor-tag-event-sync-interval: 300s
   honor-tag-event-sync-redis-prefix: "adx:honor:tag-event:"

+ 1 - 1
src/main/resources/mapper/HonorBidEventMapper.xml

@@ -42,7 +42,7 @@
         ) VALUES (
             #{record.qk}, #{record.media}, #{record.mediaTraceId}, #{record.platform},
             #{record.accountId}, #{record.eventType}, #{record.tagId},
-            #{record.price}, #{record.packageName},
+            COALESCE(#{record.price}, 0), #{record.packageName},
             #{record.mediaParams, typeHandler=com.adx.tencent.storage.typehandler.JsonStringMapTypeHandler},
             #{record.createdAtTs}
         )

+ 1 - 1
src/main/resources/schema-honor.sql

@@ -19,7 +19,7 @@ CREATE TABLE IF NOT EXISTS honor_ad_bid_events (
     account_id VARCHAR(128) COMMENT '荣耀广告主ID(advertiserId)',
     event_type VARCHAR(32) COMMENT '事件类型(impression/click),仅保留排障所需',
     tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID,对外链接也要求显式传入',
-    price BIGINT UNSIGNED COMMENT '竞价价格(分)',
+    price BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '竞价价格(分)',
     package_name VARCHAR(255) COMMENT '应用包名',
     media_params JSON COMMENT '荣耀监测参数精简白名单(trackId/advertiserId/requestId/eventTime/pkgName/tagId等)',
     created_at TIMESTAMP(3) NOT NULL COMMENT '创建时间',