/
log.go
114 lines (106 loc) · 3.9 KB
/
log.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package cli
import (
"context"
"encoding/json"
"fmt"
"io"
"os"
"sync"
"time"
"github.com/HouzuoGuo/laitos/awsinteg"
"github.com/HouzuoGuo/laitos/inet"
"github.com/HouzuoGuo/laitos/lalog"
"github.com/HouzuoGuo/laitos/misc"
"github.com/aws/aws-xray-sdk-go/awsplugins/beanstalk"
"github.com/aws/aws-xray-sdk-go/awsplugins/ec2"
"github.com/aws/aws-xray-sdk-go/awsplugins/ecs"
"github.com/aws/aws-xray-sdk-go/strategy/ctxmissing"
"github.com/aws/aws-xray-sdk-go/xray"
"github.com/aws/aws-xray-sdk-go/xraylog"
)
var (
loggerSQSClientInitOnce = new(sync.Once)
)
// LogWarningCallbackQueueMessageBody contains details of a warning log entry, ready to be serialised into JSON for sending as an SQS message.
type LogWarningCallbackQueueMessageBody struct {
UnixNanoSec int64 `json:"unix_nano_sec"`
UnixSec int64 `json:"unix_sec"`
ComponentName string `json:"component_name"`
ComponentID string `json:"component_id"`
FunctionName string `json:"function_name"`
ActorName string `json:"actor_name"`
Error error `json:"error"`
Message string `json:"message"`
}
// GetJSON returns the message body serialised into JSON.
func (messageBody LogWarningCallbackQueueMessageBody) GetJSON() []byte {
serialised, err := json.Marshal(messageBody)
if err != nil {
return []byte{}
}
return serialised
}
/*
InstallOptionalLoggerSQSCallback installs a global callback function for all laitos loggers to forward a copy of each warning
log entry to AWS SQS.
This behaviour is enabled optionally by specifying the queue URL in environment variable LAITOS_SEND_WARNING_LOG_TO_SQS_URL.
*/
func InstallOptionalLoggerSQSCallback(logger *lalog.Logger, sqsURL string) {
if misc.EnableAWSIntegration && sqsURL != "" {
logger.Info(nil, nil, "installing callback for sending logger warning messages to SQS")
loggerSQSClientInitOnce.Do(func() {
sqsClient, err := awsinteg.NewSQSClient()
if err != nil {
lalog.DefaultLogger.Warning(nil, err, "failed to initialise SQS client")
return
}
// Give SQS a copy of each warning message
lalog.GlobalLogWarningCallback = func(componentName, componentID, funcName string, actorName interface{}, err error, msg string) {
// By contract, the function body must avoid generating a warning log message to avoid infinite recurison.
sendTimeoutCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
logMessageRecord := LogWarningCallbackQueueMessageBody{
UnixNanoSec: time.Now().UnixNano(),
UnixSec: time.Now().Unix(),
ComponentName: componentName,
ComponentID: componentID,
FunctionName: funcName,
ActorName: fmt.Sprint(actorName),
Error: err,
Message: msg,
}
_ = sqsClient.SendMessage(sendTimeoutCtx, sqsURL, string(logMessageRecord.GetJSON()))
}
})
}
}
func InitialiseAWS() {
if inet.IsAWS() {
// Integrate the decorated handler with AWS x-ray. The crucial x-ray daemon program seems to be only capable of running on AWS compute resources.
_ = os.Setenv("AWS_XRAY_CONTEXT_MISSING", "LOG_ERROR")
_ = xray.Configure(xray.Config{ContextMissingStrategy: ctxmissing.NewDefaultIgnoreErrorStrategy()})
xray.SetLogger(xraylog.NewDefaultLogger(io.Discard, xraylog.LogLevelWarn))
go func() {
// These functions of aws lib take their sweet time, don't let them block main's progress. It's OK to miss a couple of traces.
beanstalk.Init()
ecs.Init()
ec2.Init()
}()
}
}
// ClearDedupBuffersInBackground periodically clears the global LRU buffers used
// for de-duplicating log messages.
func ClearDedupBuffersInBackground() {
go func() {
tickerChan := time.Tick(2 * time.Second)
for {
numDropped := lalog.NumDropped.Load()
<-tickerChan
newDropped := lalog.NumDropped.Load()
lalog.ClearDedupBuffers()
if diff := newDropped - numDropped; diff > 0 {
lalog.DefaultLogger.Warning(nil, nil, "dropped %d log messages", diff)
}
}
}()
}