@@ -166,15 +166,15 @@ func autoTargetStamp0Delta() {
166166 if cfg .format == "" {
167167 continue
168168 }
169- widths = append (widths , targetStampWidth (cfg .size , cfg .format ))
169+ widths = append (widths , targetStampDisplayWidth (cfg .size , cfg .format ))
170170 }
171171 if len (widths ) == 0 {
172172 return
173173 }
174174 width := widths [0 ]
175175 for _ , w := range widths [1 :] {
176- if w != width {
177- return
176+ if w > width {
177+ width = w
178178 }
179179 }
180180 decoder .TargetStamp0Delta = strings .Repeat (" " , width )
@@ -184,22 +184,65 @@ func targetStampWidth(size int, format string) int {
184184 return len (formatTargetStamp (size , format , 0 ))
185185}
186186
187- func renderTargetStampColumns (size int , timestamp uint64 , state * targetStampState ) string {
188- var absoluteFormat , deltaFormat string
187+ func targetStampDisplayWidth (size int , format string ) int {
188+ s := formatTargetStamp (size , format , 0 )
189+ tag , rest , found := strings .Cut (s , ":" )
190+ if found && tag != "" {
191+ return len (rest )
192+ }
193+ return len (s )
194+ }
195+
196+ func commonTargetDeltaPlaceholder () string {
197+ if decoder .TargetStamp0Delta != "" {
198+ return decoder .TargetStamp0Delta
199+ }
200+ width := 0
201+ for _ , cfg := range []struct {
202+ size int
203+ format string
204+ }{
205+ {2 , decoder .TargetStamp16Delta },
206+ {4 , decoder .TargetStamp32Delta },
207+ } {
208+ if cfg .format == "" {
209+ continue
210+ }
211+ w := targetStampDisplayWidth (cfg .size , cfg .format )
212+ if w > width {
213+ width = w
214+ }
215+ }
216+ if width == 0 {
217+ return ""
218+ }
219+ return strings .Repeat (" " , width )
220+ }
221+
222+ func targetStampFormats (size int ) (absoluteFormat , deltaFormat string ) {
189223 switch size {
190224 case 4 :
191- absoluteFormat = decoder .TargetStamp32
192- deltaFormat = decoder .TargetStamp32Delta
225+ return decoder .TargetStamp32 , decoder .TargetStamp32Delta
193226 case 2 :
194- absoluteFormat = decoder .TargetStamp16
195- deltaFormat = decoder .TargetStamp16Delta
227+ return decoder .TargetStamp16 , decoder .TargetStamp16Delta
196228 case 0 :
197- absoluteFormat = decoder .TargetStamp0
198- deltaFormat = decoder .TargetStamp0Delta
229+ return decoder .TargetStamp0 , decoder .TargetStamp0Delta
199230 default :
200- return ""
231+ return "" , ""
232+ }
233+ }
234+
235+ func renderTargetStamp (size int , timestamp uint64 ) string {
236+ absoluteFormat , _ := targetStampFormats (size )
237+ return formatTargetStamp (size , absoluteFormat , timestamp )
238+ }
239+
240+ func renderTargetDelta (size int , timestamp uint64 , state * targetStampState ) string {
241+ _ , deltaFormat := targetStampFormats (size )
242+ if deltaFormat == "" {
243+ return commonTargetDeltaPlaceholder ()
201244 }
202- return formatTargetStamp ( size , absoluteFormat , timestamp ) + formatTargetDelta (size , deltaFormat , timestamp , state )
245+ return formatTargetDelta (size , deltaFormat , timestamp , state )
203246}
204247
205248func formatTargetDelta (size int , format string , timestamp uint64 , state * targetStampState ) string {
@@ -214,7 +257,7 @@ func formatTargetDelta(size int, format string, timestamp uint64, state *targetS
214257 if ! state .hasPrev16 {
215258 state .prev16 = current
216259 state .hasPrev16 = true
217- return formatMissingTargetDelta (format )
260+ return formatMissingTargetDelta (size , format )
218261 }
219262 delta := uint16 (current - state .prev16 )
220263 state .prev16 = current
@@ -224,7 +267,7 @@ func formatTargetDelta(size int, format string, timestamp uint64, state *targetS
224267 if ! state .hasPrev32 {
225268 state .prev32 = current
226269 state .hasPrev32 = true
227- return formatMissingTargetDelta (format )
270+ return formatMissingTargetDelta (size , format )
228271 }
229272 delta := uint32 (current - state .prev32 )
230273 state .prev32 = current
@@ -234,6 +277,45 @@ func formatTargetDelta(size int, format string, timestamp uint64, state *targetS
234277 }
235278}
236279
280+ func formatTargetDeltaValue (size int , timestampFormat string , timestamp uint64 ) string {
281+ switch size {
282+ case 4 :
283+ switch timestampFormat {
284+ case "ms" , "hh:mm:ss,ms" :
285+ ms := timestamp % 1000
286+ sec := (timestamp - ms ) / 1000 % 60
287+ min := (timestamp - ms - 1000 * sec ) / 60000 % 60
288+ hour := (timestamp - ms - 1000 * sec - 60000 * min ) / 3600000
289+ return fmt .Sprintf ("%2d:%02d:%02d,%03d" , hour , min , sec , ms )
290+ case "us" , "µs" , "ssss,ms_µs" :
291+ us := timestamp % 1000
292+ ms := (timestamp - us ) / 1000 % 1000
293+ sd := (timestamp - 1000 * ms ) / 1000000
294+ return fmt .Sprintf ("%4d,%03d_%03d" , sd , ms , us )
295+ default :
296+ return fmt .Sprintf (timestampFormat , timestamp )
297+ }
298+ case 2 :
299+ switch timestampFormat {
300+ case "ms" , "s,ms" :
301+ ms := timestamp % 1000
302+ sec := (timestamp - ms ) / 1000
303+ return fmt .Sprintf (" %2d,%03d" , sec , ms )
304+ case "us" , "µs" , "ms_µs" :
305+ us := timestamp % 1000
306+ ms := (timestamp - us ) / 1000 % 1000
307+ return fmt .Sprintf (" %2d_%03d" , ms , us )
308+ default :
309+ return fmt .Sprintf (timestampFormat , timestamp )
310+ }
311+ case 0 :
312+ if timestampFormat != "" {
313+ return fmt .Sprint (timestampFormat )
314+ }
315+ }
316+ return ""
317+ }
318+
237319func formatTargetStamp (size int , format string , timestamp uint64 ) string {
238320 switch size {
239321 case 4 :
@@ -303,10 +385,13 @@ func formatTargetStamp16(format string, timestamp uint64) string {
303385 }
304386}
305387
306- func formatMissingTargetDelta (format string ) string {
388+ func formatMissingTargetDelta (size int , format string ) string {
307389 prefix , width , leftAlign , suffix , ok := splitSingleFormatDirective (format )
308390 if ! ok {
309- return "-"
391+ if isBuiltinTargetStampFormat (size , format ) {
392+ return strings .Repeat (" " , targetStampDisplayWidth (size , format ))
393+ }
394+ return formatTargetStamp (size , format , 0 )
310395 }
311396 marker := "-"
312397 if width > 0 {
@@ -319,6 +404,22 @@ func formatMissingTargetDelta(format string) string {
319404 return prefix + marker + suffix
320405}
321406
407+ func isBuiltinTargetStampFormat (size int , format string ) bool {
408+ switch size {
409+ case 4 :
410+ switch format {
411+ case "ms" , "hh:mm:ss,ms" , "us" , "µs" , "ssss,ms_µs" :
412+ return true
413+ }
414+ case 2 :
415+ switch format {
416+ case "ms" , "s,ms" , "us" , "µs" , "ms_µs" :
417+ return true
418+ }
419+ }
420+ return false
421+ }
422+
322423func splitSingleFormatDirective (format string ) (prefix string , width int , leftAlign bool , suffix string , ok bool ) {
323424 for i := 0 ; i < len (format ); i ++ {
324425 if format [i ] != '%' {
@@ -417,11 +518,20 @@ func decodeAndComposeLoop(w io.Writer, sw *emitter.TriceLineComposer, dec decode
417518
418519 var s string
419520 if logLineStart {
420- s = renderTargetStampColumns (decoder .TargetTimestampSize , decoder .TargetTimestamp , & state )
421- _ , err := sw .Write ([]byte (s ))
422- msg .OnErr (err )
423- _ , err = sw .Write ([]byte ("default: " ))
424- msg .OnErr (err )
521+ s = renderTargetStamp (decoder .TargetTimestampSize , decoder .TargetTimestamp )
522+ if s != "" {
523+ _ , err := sw .Write ([]byte (s ))
524+ msg .OnErr (err )
525+ _ , err = sw .Write ([]byte ("default: " ))
526+ msg .OnErr (err )
527+ }
528+ s = renderTargetDelta (decoder .TargetTimestampSize , decoder .TargetTimestamp , & state )
529+ if s != "" {
530+ _ , err := sw .Write ([]byte (s ))
531+ msg .OnErr (err )
532+ _ , err = sw .Write ([]byte ("default: " ))
533+ msg .OnErr (err )
534+ }
425535 }
426536 // write ID only if enabled and line start.
427537 if logLineStart && decoder .ShowID != "" {
0 commit comments