3232import com .tencent .bk .job .logsvr .model .ScriptLogQuery ;
3333import com .tencent .bk .job .logsvr .model .ScriptTaskLogDoc ;
3434import com .tencent .bk .job .logsvr .model .TaskExecuteObjectLog ;
35+ import com .tencent .bk .job .common .util .date .DateUtils ;
36+ import com .tencent .bk .job .logsvr .model .service .FileTaskTimeAndRawLogDTO ;
37+ import com .tencent .bk .job .logsvr .model .service .ServiceFileTaskLogDTO ;
3538import com .tencent .bk .job .logsvr .mongo .FileLogsCollectionLoader ;
3639import com .tencent .bk .job .logsvr .mongo .LogCollectionFactory ;
3740import com .tencent .bk .job .logsvr .mongo .LogCollectionLoaderFactory ;
4649import org .springframework .test .context .ActiveProfiles ;
4750import org .springframework .test .context .TestPropertySource ;
4851
52+ import java .time .ZoneId ;
53+ import java .time .temporal .ChronoUnit ;
4954import java .util .ArrayList ;
5055import java .util .Collections ;
5156import java .util .List ;
@@ -294,6 +299,7 @@ void testSaveScriptLogV2() {
294299
295300 @ Nested
296301 @ DisplayName ("测试保存文件分发日志" )
302+ @ SuppressWarnings ("deprecation" )
297303 class SaveFileLogTest {
298304
299305 @ Test
@@ -357,10 +363,10 @@ void testSaveFileLog() {
357363 assertThat (resultFileTaskLog1 .getSize ()).isEqualTo ("100MB" );
358364 assertThat (resultFileTaskLog1 .getSpeed ()).isEqualTo ("100KB/S" );
359365 assertThat (resultFileTaskLog1 .getProcess ()).isEqualTo ("50%" );
360- // 验证contentList包含1个map
361- assertThat (resultFileTaskLog1 .getContentList ()).hasSize (1 );
362- assertThat (resultFileTaskLog1 .getContentList ().get (0 )).isInstanceOf (Map .class );
363- Map <String , Object > logEntry1 = (Map <String , Object >) resultFileTaskLog1 .getContentList ().get (0 );
366+ // 验证timeLogList包含1条LogEntry(Map对象)
367+ assertThat (resultFileTaskLog1 .getTimeLogList ()).hasSize (1 );
368+ assertThat (resultFileTaskLog1 .getTimeLogList ().get (0 )).isInstanceOf (Map .class );
369+ Map <String , Object > logEntry1 = (Map <String , Object >) resultFileTaskLog1 .getTimeLogList ().get (0 );
364370 assertThat (logEntry1 .get ("logTime" )).isEqualTo (1596078000000L );
365371 assertThat (logEntry1 .get ("content" )).isEqualTo ("Downloading...\n " );
366372
@@ -415,16 +421,14 @@ void testSaveFileLog() {
415421 assertThat (resultFileTaskLog1 .getSize ()).isEqualTo ("100MB" );
416422 assertThat (resultFileTaskLog1 .getSpeed ()).isEqualTo ("0KB/S" );
417423 assertThat (resultFileTaskLog1 .getProcess ()).isEqualTo ("100%" );
418- // 验证contentList包含2个map
419- assertThat (resultFileTaskLog1 .getContentList ()).hasSize (2 );
424+ // 验证timeLogList包含2条LogEntry(Map对象)
425+ assertThat (resultFileTaskLog1 .getTimeLogList ()).hasSize (2 );
420426 // 第1条
421- assertThat (resultFileTaskLog1 .getContentList ().get (0 )).isInstanceOf (Map .class );
422- Map <String , Object > logEntry1Final = (Map <String , Object >) resultFileTaskLog1 .getContentList ().get (0 );
427+ Map <String , Object > logEntry1Final = (Map <String , Object >) resultFileTaskLog1 .getTimeLogList ().get (0 );
423428 assertThat (logEntry1Final .get ("logTime" )).isEqualTo (1596078000000L );
424429 assertThat (logEntry1Final .get ("content" )).isEqualTo ("Downloading...\n " );
425430 // 第2条
426- assertThat (resultFileTaskLog1 .getContentList ().get (1 )).isInstanceOf (Map .class );
427- Map <String , Object > logEntry2 = (Map <String , Object >) resultFileTaskLog1 .getContentList ().get (1 );
431+ Map <String , Object > logEntry2 = (Map <String , Object >) resultFileTaskLog1 .getTimeLogList ().get (1 );
428432 assertThat (logEntry2 .get ("logTime" )).isEqualTo (1596079800000L );
429433 assertThat (logEntry2 .get ("content" )).isEqualTo ("Download success\n " );
430434 }
@@ -434,7 +438,8 @@ void testSaveFileLog() {
434438 void testCompatiblySaveFileLog () {
435439 long stepInstanceId = 2L ;
436440
437- // 第一次写入:使用老版本方式(只有content字段)
441+ // === 第一次写入:使用老版本方式(只有content字段) ===
442+ // 老 logsvr 只写 contentList(纯String),不写 timeLogList
438443 FileTaskLogDoc fileTaskLog1 = buildFileTaskDetailLog (
439444 FileTaskModeEnum .DOWNLOAD .getValue (),
440445 102L ,
@@ -453,7 +458,7 @@ void testCompatiblySaveFileLog() {
453458 "100KB/S" ,
454459 "100MB" ,
455460 "50%" );
456- oldFileTaskLogAddContent (fileTaskLog1 , "[2020-07-30 11:00:00 ] Downloading1...\n " );
461+ oldFileTaskLogAddContent (fileTaskLog1 , "[" + formatTime ( 1596078000000L ) + " ] Downloading1...\n " );
457462
458463 List <FileTaskLogDoc > fileTaskLogList = new ArrayList <>();
459464 fileTaskLogList .add (fileTaskLog1 );
@@ -486,12 +491,21 @@ void testCompatiblySaveFileLog() {
486491 assertThat (resultFileTaskLog1 .getSize ()).isEqualTo ("100MB" );
487492 assertThat (resultFileTaskLog1 .getSpeed ()).isEqualTo ("100KB/S" );
488493 assertThat (resultFileTaskLog1 .getProcess ()).isEqualTo ("50%" );
489- // 验证contentList包含老格式数据(字符串 )
494+ // 验证contentList包含1条纯String(老版写入 )
490495 assertThat (resultFileTaskLog1 .getContentList ()).hasSize (1 );
491- assertThat (resultFileTaskLog1 .getContentList ().get (0 )).isInstanceOf (String .class );
492- assertThat (resultFileTaskLog1 .getContentList ().get (0 )).isEqualTo ("[2020-07-30 11:00:00] Downloading1...\n " );
493-
494- // 第二次写入:使用新版本方式(writeContentList字段,包含LogEntry对象)
496+ assertThat (resultFileTaskLog1 .getContentList ().get (0 ))
497+ .isEqualTo ("[" + formatTime (1596078000000L ) + "] Downloading1...\n " );
498+ // 验证timeLogList为null(老版不写timeLogList)
499+ assertThat (resultFileTaskLog1 .getTimeLogList ()).isNull ();
500+ // 验证 toServiceFileTaskLogDTO 兼容读取(timeLogList为空 → 降级使用contentList,time=null)
501+ ServiceFileTaskLogDTO serviceDTO1 = resultFileTaskLog1 .toServiceFileTaskLogDTO ();
502+ assertThat (serviceDTO1 .getContentList ()).hasSize (1 );
503+ assertThat (serviceDTO1 .getContentList ().get (0 ).getTime ()).isNull ();
504+ assertThat (serviceDTO1 .getContentList ().get (0 ).getRawLog ())
505+ .isEqualTo ("[" + formatTime (1596078000000L ) + "] Downloading1...\n " );
506+
507+ // === 第二次写入:使用新版本方式(writeContentList字段,包含LogEntry对象) ===
508+ // 新 logsvr 同时写 timeLogList(LogEntry对象)和 contentList(拼接的纯String)
495509 fileTaskLog1 = buildFileTaskDetailLog (
496510 FileTaskModeEnum .DOWNLOAD .getValue (),
497511 102L ,
@@ -510,9 +524,8 @@ void testCompatiblySaveFileLog() {
510524 "100KB/S" ,
511525 "100MB" ,
512526 "60%" );
513- // 设置writeContentList(新版本格式)
527+ // 设置writeContentList(新版本格式),timestamp=1596078180000L
514528 List <FileTaskLogDoc .LogEntry > writeContentList = new ArrayList <>();
515- // 1596078180000L 对应 东八区时间 2020-07-30 11:03:00
516529 writeContentList .add (new FileTaskLogDoc .LogEntry (1596078180000L , "Downloading2...\n " ));
517530 fillWriteList (fileTaskLog1 , writeContentList );
518531
@@ -525,16 +538,31 @@ void testCompatiblySaveFileLog() {
525538 fileLogDocs = logService .listFileLogs (searchRequest );
526539 assertThat (fileLogDocs ).hasSize (1 );
527540 resultFileTaskLog1 = fileLogDocs .get (0 );
528- // 验证contentList包含2条数据:1条老格式(字符串)+ 1条新格式(LogEntry对象)
541+ // 验证contentList包含2条纯String:1条老版 + 1条新版拼接的
529542 assertThat (resultFileTaskLog1 .getContentList ()).hasSize (2 );
530- assertThat (resultFileTaskLog1 .getContentList ().get (0 )).isInstanceOf (String .class );
531- assertThat (resultFileTaskLog1 .getContentList ().get (0 )).isEqualTo ("[2020-07-30 11:00:00] Downloading1...\n " );
532- assertThat (resultFileTaskLog1 .getContentList ().get (1 )).isInstanceOf (Map .class );
533- Map <String , Object > logEntry = (Map <String , Object >) resultFileTaskLog1 .getContentList ().get (1 );
543+ // 第1条:老版写入的纯String,原样保留
544+ assertThat (resultFileTaskLog1 .getContentList ().get (0 ))
545+ .isEqualTo ("[" + formatTime (1596078000000L ) + "] Downloading1...\n " );
546+ // 第2条:新版写入时拼接的 "[timestamp转化后的时间] log" 格式(content自带换行符)
547+ assertThat (resultFileTaskLog1 .getContentList ().get (1 ))
548+ .isEqualTo ("[" + formatTime (1596078180000L ) + "] Downloading2...\n " );
549+ // 验证timeLogList包含1条LogEntry(只有新版写入的那条)
550+ assertThat (resultFileTaskLog1 .getTimeLogList ()).hasSize (1 );
551+ Map <String , Object > logEntry = (Map <String , Object >) resultFileTaskLog1 .getTimeLogList ().get (0 );
534552 assertThat (logEntry .get ("logTime" )).isEqualTo (1596078180000L );
535553 assertThat (logEntry .get ("content" )).isEqualTo ("Downloading2...\n " );
536-
537- // 第三次写入:再次使用老版本方式(只有content字段)
554+ // 验证 toServiceFileTaskLogDTO 兼容读取
555+ // timeLogList.size(1) != contentList.size(2) → 降级使用contentList,所有time=null
556+ ServiceFileTaskLogDTO serviceDTO2 = resultFileTaskLog1 .toServiceFileTaskLogDTO ();
557+ assertThat (serviceDTO2 .getContentList ()).hasSize (2 );
558+ assertThat (serviceDTO2 .getContentList ().get (0 ).getTime ()).isNull ();
559+ assertThat (serviceDTO2 .getContentList ().get (0 ).getRawLog ())
560+ .isEqualTo ("[" + formatTime (1596078000000L ) + "] Downloading1...\n " );
561+ assertThat (serviceDTO2 .getContentList ().get (1 ).getTime ()).isNull ();
562+ assertThat (serviceDTO2 .getContentList ().get (1 ).getRawLog ())
563+ .isEqualTo ("[" + formatTime (1596078180000L ) + "] Downloading2...\n " );
564+
565+ // === 第三次写入:再次使用老版本方式(只有content字段) ===
538566 fileTaskLog1 = buildFileTaskDetailLog (
539567 FileTaskModeEnum .DOWNLOAD .getValue (),
540568 102L ,
@@ -553,7 +581,7 @@ void testCompatiblySaveFileLog() {
553581 "0KB/S" ,
554582 "100MB" ,
555583 "100%" );
556- oldFileTaskLogAddContent (fileTaskLog1 , "[2020-07-30 11:30:00 ] Downloading3...\n " );
584+ oldFileTaskLogAddContent (fileTaskLog1 , "[" + formatTime ( 1596079800000L ) + " ] Downloading3...\n " );
557585
558586 fileTaskLogList .clear ();
559587 fileTaskLogList .add (fileTaskLog1 );
@@ -581,19 +609,38 @@ void testCompatiblySaveFileLog() {
581609 assertThat (resultFileTaskLog1 .getSpeed ()).isEqualTo ("0KB/S" );
582610 assertThat (resultFileTaskLog1 .getProcess ()).isEqualTo ("100%" );
583611
584- // 验证contentList包含3条数据 :老格式 + 新格式 + 老格式
612+ // 验证contentList包含3条纯String :老格式 + 新格式拼接的 + 老格式
585613 assertThat (resultFileTaskLog1 .getContentList ()).hasSize (3 );
586- // 第1条:老格式(字符串)
587- assertThat (resultFileTaskLog1 .getContentList ().get (0 )).isInstanceOf (String .class );
588- assertThat (resultFileTaskLog1 .getContentList ().get (0 )).isEqualTo ("[2020-07-30 11:00:00] Downloading1...\n " );
589- // 第2条:新格式(LogEntry对象)
590- assertThat (resultFileTaskLog1 .getContentList ().get (1 )).isInstanceOf (Map .class );
591- Map <String , Object > logEntry2 = (Map <String , Object >) resultFileTaskLog1 .getContentList ().get (1 );
614+ // 第1条:老版写入的 "[时间] 日志" 格式
615+ assertThat (resultFileTaskLog1 .getContentList ().get (0 ))
616+ .isEqualTo ("[" + formatTime (1596078000000L ) + "] Downloading1...\n " );
617+ // 第2条:新版写入时 timestamp 转化后拼接的 "[时间] 日志" 格式(content自带换行符)
618+ assertThat (resultFileTaskLog1 .getContentList ().get (1 ))
619+ .isEqualTo ("[" + formatTime (1596078180000L ) + "] Downloading2...\n " );
620+ // 第3条:老版写入的 "[时间] 日志" 格式
621+ assertThat (resultFileTaskLog1 .getContentList ().get (2 ))
622+ .isEqualTo ("[" + formatTime (1596079800000L ) + "] Downloading3...\n " );
623+
624+ // 验证timeLogList只包含1条(只有第二次新版写入时才push到timeLogList)
625+ assertThat (resultFileTaskLog1 .getTimeLogList ()).hasSize (1 );
626+ @ SuppressWarnings ("unchecked" )
627+ Map <String , Object > logEntry2 = (Map <String , Object >) resultFileTaskLog1 .getTimeLogList ().get (0 );
592628 assertThat (logEntry2 .get ("logTime" )).isEqualTo (1596078180000L );
593629 assertThat (logEntry2 .get ("content" )).isEqualTo ("Downloading2...\n " );
594- // 第3条:老格式(字符串)
595- assertThat (resultFileTaskLog1 .getContentList ().get (2 )).isInstanceOf (String .class );
596- assertThat (resultFileTaskLog1 .getContentList ().get (2 )).isEqualTo ("[2020-07-30 11:30:00] Downloading3...\n " );
630+
631+ // 验证 toServiceFileTaskLogDTO 兼容读取
632+ // timeLogList.size(1) != contentList.size(3) → 降级使用contentList,所有time=null
633+ ServiceFileTaskLogDTO serviceDTO3 = resultFileTaskLog1 .toServiceFileTaskLogDTO ();
634+ assertThat (serviceDTO3 .getContentList ()).hasSize (3 );
635+ for (FileTaskTimeAndRawLogDTO item : serviceDTO3 .getContentList ()) {
636+ assertThat (item .getTime ()).isNull ();
637+ }
638+ assertThat (serviceDTO3 .getContentList ().get (0 ).getRawLog ())
639+ .isEqualTo ("[" + formatTime (1596078000000L ) + "] Downloading1...\n " );
640+ assertThat (serviceDTO3 .getContentList ().get (1 ).getRawLog ())
641+ .isEqualTo ("[" + formatTime (1596078180000L ) + "] Downloading2...\n " );
642+ assertThat (serviceDTO3 .getContentList ().get (2 ).getRawLog ())
643+ .isEqualTo ("[" + formatTime (1596079800000L ) + "] Downloading3...\n " );
597644 }
598645 }
599646
@@ -630,6 +677,18 @@ void fillWriteList(FileTaskLogDoc doc, List<FileTaskLogDoc.LogEntry> writeConten
630677 doc .setWriteContentList (writeContentList );
631678 }
632679
680+ /**
681+ * 使用系统默认时区将时间戳格式化为时间字符串,与 pushFileTaskLogContentCompatibly 逻辑一致
682+ */
683+ private String formatTime (long timestampMillis ) {
684+ return DateUtils .formatUnixTimestamp (
685+ timestampMillis ,
686+ ChronoUnit .MILLIS ,
687+ DateUtils .FILE_TASK_LOG_FORMAT ,
688+ ZoneId .systemDefault ()
689+ );
690+ }
691+
633692 FileTaskLogDoc buildFileTaskDetailLog (Integer mode ,
634693 Long hostId ,
635694 Long srcHostId ,
0 commit comments