1
0
mirror of https://github.com/raseels-repos/golang-saas-starter-kit.git synced 2025-07-03 00:58:13 +02:00

Imported github.com/ardanlabs/service as base example project

This commit is contained in:
Lee Brown
2019-05-16 10:39:25 -04:00
parent a5af03321d
commit e6453bae45
304 changed files with 51148 additions and 0 deletions

View File

@ -0,0 +1,46 @@
package model
import (
"encoding/json"
"errors"
"time"
)
// ErrValidTimestampRequired error
var ErrValidTimestampRequired = errors.New("valid annotation timestamp required")
// Annotation associates an event that explains latency with a timestamp.
type Annotation struct {
Timestamp time.Time
Value string
}
// MarshalJSON implements custom JSON encoding
func (a *Annotation) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Timestamp int64 `json:"timestamp"`
Value string `json:"value"`
}{
Timestamp: a.Timestamp.Round(time.Microsecond).UnixNano() / 1e3,
Value: a.Value,
})
}
// UnmarshalJSON implements custom JSON decoding
func (a *Annotation) UnmarshalJSON(b []byte) error {
type Alias Annotation
annotation := &struct {
TimeStamp uint64 `json:"timestamp"`
*Alias
}{
Alias: (*Alias)(a),
}
if err := json.Unmarshal(b, &annotation); err != nil {
return err
}
if annotation.TimeStamp < 1 {
return ErrValidTimestampRequired
}
a.Timestamp = time.Unix(0, int64(annotation.TimeStamp)*1e3)
return nil
}

View File

@ -0,0 +1,9 @@
/*
Package model contains the Zipkin V2 model which is used by the Zipkin Go
tracer implementation.
Third party instrumentation libraries can use the model and transport packages
found in this Zipkin Go library to directly interface with the Zipkin Server or
Zipkin Collectors without the need to use the tracer implementation itself.
*/
package model

View File

@ -0,0 +1,17 @@
package model
import "net"
// Endpoint holds the network context of a node in the service graph.
type Endpoint struct {
ServiceName string `json:"serviceName,omitempty"`
IPv4 net.IP `json:"ipv4,omitempty"`
IPv6 net.IP `json:"ipv6,omitempty"`
Port uint16 `json:"port,omitempty"`
}
// Empty returns if all Endpoint properties are empty / unspecified.
func (e *Endpoint) Empty() bool {
return e == nil ||
(e.ServiceName == "" && e.Port == 0 && len(e.IPv4) == 0 && len(e.IPv6) == 0)
}

View File

@ -0,0 +1,13 @@
package model
// Kind clarifies context of timestamp, duration and remoteEndpoint in a span.
type Kind string
// Available Kind values
const (
Undetermined Kind = ""
Client Kind = "CLIENT"
Server Kind = "SERVER"
Producer Kind = "PRODUCER"
Consumer Kind = "CONSUMER"
)

View File

@ -0,0 +1,124 @@
package model
import (
"encoding/json"
"errors"
"time"
)
// unmarshal errors
var (
ErrValidTraceIDRequired = errors.New("valid traceId required")
ErrValidIDRequired = errors.New("valid span id required")
ErrValidDurationRequired = errors.New("valid duration required")
)
// SpanContext holds the context of a Span.
type SpanContext struct {
TraceID TraceID `json:"traceId"`
ID ID `json:"id"`
ParentID *ID `json:"parentId,omitempty"`
Debug bool `json:"debug,omitempty"`
Sampled *bool `json:"-"`
Err error `json:"-"`
}
// SpanModel structure.
//
// If using this library to instrument your application you will not need to
// directly access or modify this representation. The SpanModel is exported for
// use cases involving 3rd party Go instrumentation libraries desiring to
// export data to a Zipkin server using the Zipkin V2 Span model.
type SpanModel struct {
SpanContext
Name string `json:"name,omitempty"`
Kind Kind `json:"kind,omitempty"`
Timestamp time.Time `json:"timestamp,omitempty"`
Duration time.Duration `json:"duration,omitempty"`
Shared bool `json:"shared,omitempty"`
LocalEndpoint *Endpoint `json:"localEndpoint,omitempty"`
RemoteEndpoint *Endpoint `json:"remoteEndpoint,omitempty"`
Annotations []Annotation `json:"annotations,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
}
// MarshalJSON exports our Model into the correct format for the Zipkin V2 API.
func (s SpanModel) MarshalJSON() ([]byte, error) {
type Alias SpanModel
var timestamp int64
if !s.Timestamp.IsZero() {
if s.Timestamp.Unix() < 1 {
// Zipkin does not allow Timestamps before Unix epoch
return nil, ErrValidTimestampRequired
}
timestamp = s.Timestamp.Round(time.Microsecond).UnixNano() / 1e3
}
if s.Duration < time.Microsecond {
if s.Duration < 0 {
// negative duration is not allowed and signals a timing logic error
return nil, ErrValidDurationRequired
} else if s.Duration > 0 {
// sub microsecond durations are reported as 1 microsecond
s.Duration = 1 * time.Microsecond
}
} else {
// Duration will be rounded to nearest microsecond representation.
//
// NOTE: Duration.Round() is not available in Go 1.8 which we still support.
// To handle microsecond resolution rounding we'll add 500 nanoseconds to
// the duration. When truncated to microseconds in the call to marshal, it
// will be naturally rounded. See TestSpanDurationRounding in span_test.go
s.Duration += 500 * time.Nanosecond
}
if s.LocalEndpoint.Empty() {
s.LocalEndpoint = nil
}
if s.RemoteEndpoint.Empty() {
s.RemoteEndpoint = nil
}
return json.Marshal(&struct {
Timestamp int64 `json:"timestamp,omitempty"`
Duration int64 `json:"duration,omitempty"`
Alias
}{
Timestamp: timestamp,
Duration: s.Duration.Nanoseconds() / 1e3,
Alias: (Alias)(s),
})
}
// UnmarshalJSON imports our Model from a Zipkin V2 API compatible span
// representation.
func (s *SpanModel) UnmarshalJSON(b []byte) error {
type Alias SpanModel
span := &struct {
TimeStamp uint64 `json:"timestamp,omitempty"`
Duration uint64 `json:"duration,omitempty"`
*Alias
}{
Alias: (*Alias)(s),
}
if err := json.Unmarshal(b, &span); err != nil {
return err
}
if s.ID < 1 {
return ErrValidIDRequired
}
if span.TimeStamp > 0 {
s.Timestamp = time.Unix(0, int64(span.TimeStamp)*1e3)
}
s.Duration = time.Duration(span.Duration*1e3) * time.Nanosecond
if s.LocalEndpoint.Empty() {
s.LocalEndpoint = nil
}
if s.RemoteEndpoint.Empty() {
s.RemoteEndpoint = nil
}
return nil
}

View File

@ -0,0 +1,30 @@
package model
import (
"fmt"
"strconv"
)
// ID type
type ID uint64
// String outputs the 64-bit ID as hex string.
func (i ID) String() string {
return fmt.Sprintf("%016x", uint64(i))
}
// MarshalJSON serializes an ID type (SpanID, ParentSpanID) to HEX.
func (i ID) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("%q", i.String())), nil
}
// UnmarshalJSON deserializes an ID type (SpanID, ParentSpanID) from HEX.
func (i *ID) UnmarshalJSON(b []byte) (err error) {
var id uint64
if len(b) < 3 {
return nil
}
id, err = strconv.ParseUint(string(b[1:len(b)-1]), 16, 64)
*i = ID(id)
return err
}

View File

@ -0,0 +1,59 @@
package model
import (
"fmt"
"strconv"
)
// TraceID is a 128 bit number internally stored as 2x uint64 (high & low).
// In case of 64 bit traceIDs, the value can be found in Low.
type TraceID struct {
High uint64
Low uint64
}
// Empty returns if TraceID has zero value.
func (t TraceID) Empty() bool {
return t.Low == 0 && t.High == 0
}
// String outputs the 128-bit traceID as hex string.
func (t TraceID) String() string {
if t.High == 0 {
return fmt.Sprintf("%016x", t.Low)
}
return fmt.Sprintf("%016x%016x", t.High, t.Low)
}
// TraceIDFromHex returns the TraceID from a hex string.
func TraceIDFromHex(h string) (t TraceID, err error) {
if len(h) > 16 {
if t.High, err = strconv.ParseUint(h[0:len(h)-16], 16, 64); err != nil {
return
}
t.Low, err = strconv.ParseUint(h[len(h)-16:], 16, 64)
return
}
t.Low, err = strconv.ParseUint(h, 16, 64)
return
}
// MarshalJSON custom JSON serializer to export the TraceID in the required
// zero padded hex representation.
func (t TraceID) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("%q", t.String())), nil
}
// UnmarshalJSON custom JSON deserializer to retrieve the traceID from the hex
// encoded representation.
func (t *TraceID) UnmarshalJSON(traceID []byte) error {
if len(traceID) < 3 {
return ErrValidTraceIDRequired
}
tID, err := TraceIDFromHex(string(traceID[1 : len(traceID)-1]))
if err != nil {
return err
}
*t = tID
return nil
}