@@ -7,6 +7,11 @@ package resty
7
7
8
8
import (
9
9
"bytes"
10
+ "crypto/md5"
11
+ "crypto/rand"
12
+ "encoding/binary"
13
+ "encoding/hex"
14
+ "errors"
10
15
"fmt"
11
16
"io"
12
17
"log"
@@ -17,6 +22,7 @@ import (
17
22
"runtime"
18
23
"sort"
19
24
"strings"
25
+ "sync/atomic"
20
26
"time"
21
27
)
22
28
@@ -348,11 +354,16 @@ func requestDebugLogger(c *Client, r *Request) {
348
354
reqLog += "~~~ REQUEST ~~~\n " +
349
355
fmt .Sprintf ("%s %s %s\n " , r .Method , rr .URL .RequestURI (), rr .Proto ) +
350
356
fmt .Sprintf ("HOST : %s\n " , rr .URL .Host ) +
351
- fmt .Sprintf ("ATTEMPT: %d\n " , r .Attempt ) +
352
357
fmt .Sprintf ("HEADERS:\n %s\n " , composeHeaders (rl .Header )) +
353
358
fmt .Sprintf ("BODY :\n %v\n " , rl .Body ) +
354
359
"------------------------------------------------------------------------------\n "
355
360
361
+ if len (r .RetryTraceID ) > 0 {
362
+ reqLog += fmt .Sprintf ("RETRY TRACE ID: %s\n " , r .RetryTraceID ) +
363
+ fmt .Sprintf ("ATTEMPT : %d\n " , r .Attempt ) +
364
+ "------------------------------------------------------------------------------\n "
365
+ }
366
+
356
367
r .initValuesMap ()
357
368
r .values [debugRequestLogKey ] = reqLog
358
369
}
@@ -392,3 +403,88 @@ func responseDebugLogger(c *Client, res *Response) {
392
403
393
404
res .Request .log .Debugf ("%s" , debugLog )
394
405
}
406
+
407
+ //‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
408
+ // GUID generation
409
+ // Code inspired from mgo/bson ObjectId
410
+ // Code obtained from https://github.com/go-aah/aah/blob/edge/essentials/guid.go
411
+ //___________________________________
412
+
413
+ var (
414
+ // guidCounter is atomically incremented when generating a new GUID
415
+ // using UniqueID() function. It's used as a counter part of an id.
416
+ guidCounter = readRandomUint32 ()
417
+
418
+ // machineID stores machine id generated once and used in subsequent calls
419
+ // to UniqueId function.
420
+ machineID = readMachineID ()
421
+
422
+ // processID is current Process Id
423
+ processID = os .Getpid ()
424
+ )
425
+
426
+ // newGUID method returns a new Globally Unique Identifier (GUID).
427
+ //
428
+ // The 12-byte `UniqueId` consists of-
429
+ // - 4-byte value representing the seconds since the Unix epoch,
430
+ // - 3-byte machine identifier,
431
+ // - 2-byte process id, and
432
+ // - 3-byte counter, starting with a random value.
433
+ //
434
+ // Uses Mongo Object ID algorithm to generate globally unique ids -
435
+ // https://docs.mongodb.com/manual/reference/method/ObjectId/
436
+ func newGUID () string {
437
+ var b [12 ]byte
438
+ // Timestamp, 4 bytes, big endian
439
+ binary .BigEndian .PutUint32 (b [:], uint32 (time .Now ().Unix ()))
440
+
441
+ // Machine, first 3 bytes of md5(hostname)
442
+ b [4 ], b [5 ], b [6 ] = machineID [0 ], machineID [1 ], machineID [2 ]
443
+
444
+ // Pid, 2 bytes, specs don't specify endianness, but we use big endian.
445
+ b [7 ], b [8 ] = byte (processID >> 8 ), byte (processID )
446
+
447
+ // Increment, 3 bytes, big endian
448
+ i := atomic .AddUint32 (& guidCounter , 1 )
449
+ b [9 ], b [10 ], b [11 ] = byte (i >> 16 ), byte (i >> 8 ), byte (i )
450
+
451
+ return hex .EncodeToString (b [:])
452
+ }
453
+
454
+ var ioReadFull = io .ReadFull
455
+
456
+ // readRandomUint32 returns a random guidCounter.
457
+ func readRandomUint32 () uint32 {
458
+ var b [4 ]byte
459
+ if _ , err := ioReadFull (rand .Reader , b [:]); err == nil {
460
+ return (uint32 (b [0 ]) << 0 ) | (uint32 (b [1 ]) << 8 ) | (uint32 (b [2 ]) << 16 ) | (uint32 (b [3 ]) << 24 )
461
+ }
462
+
463
+ // To initialize package unexported variable 'guidCounter'.
464
+ // This panic would happen at program startup, so no worries at runtime panic.
465
+ panic (errors .New ("resty - guid: unable to generate random object id" ))
466
+ }
467
+
468
+ var osHostname = os .Hostname
469
+
470
+ // readMachineID generates and returns a machine id.
471
+ // If this function fails to get the hostname it will cause a runtime error.
472
+ func readMachineID () []byte {
473
+ var sum [3 ]byte
474
+ id := sum [:]
475
+
476
+ if hostname , err := osHostname (); err == nil {
477
+ hw := md5 .New ()
478
+ _ , _ = hw .Write ([]byte (hostname ))
479
+ copy (id , hw .Sum (nil ))
480
+ return id
481
+ }
482
+
483
+ if _ , err := ioReadFull (rand .Reader , id ); err == nil {
484
+ return id
485
+ }
486
+
487
+ // To initialize package unexported variable 'machineID'.
488
+ // This panic would happen at program startup, so no worries at runtime panic.
489
+ panic (errors .New ("resty - guid: unable to get hostname and random bytes" ))
490
+ }
0 commit comments