-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathatshook.go
131 lines (106 loc) · 3.22 KB
/
atshook.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package atshook
import (
"github.com/sirupsen/logrus"
"github.com/Azure/azure-sdk-for-go/storage"
"os"
"strconv"
"errors"
)
const (
// TableAlreadyExists indicates table already exists in Azure.
tableAlreadyExists string = "TableAlreadyExists"
timestampID string = "LogTimestamp"
levelID string = "Level"
messageID string = "Message"
)
// AtsHook to handle writing to Azure Table Storage
type AtsHook struct {
// Azure specifics
accountName string
accountKey string
tableName string
// azure table client
tableCli storage.TableServiceClient
table *storage.Table
levels []logrus.Level
formatter logrus.Formatter
}
// NewHook creates a new instance of atsHook.
// The accountName, accountKey and tableName for Azure are required.
func NewHook(accountName string, accountKey string, tableName string, level logrus.Level) *AtsHook {
levels := []logrus.Level{}
for _, lev := range logrus.AllLevels {
if lev <= level {
levels = append(levels, lev)
}
}
hook := &AtsHook{}
client, err := createTableClient(accountName, accountKey)
if err != nil {
//fmt.Printf("Unable to create client for Azure Table Storage hook %s", err)
return nil // is nil valid?
}
hook.tableCli = client.GetTableService()
table, err := createTable(hook.tableCli, tableName)
if err != nil {
// cant log... but return no hook!
return nil
}
hook.table = table
hook.accountName = accountName
hook.accountKey = accountKey
hook.tableName = tableName
hook.levels = levels
return hook
}
func createTable( tableCli storage.TableServiceClient , tableName string) (*storage.Table, error) {
table := tableCli.GetTableReference(tableName)
err := table.Create( 30, storage.EmptyPayload, nil )
if err != nil {
azureErr, ok := err.(storage.AzureStorageServiceError)
if !ok {
// error... what to do? Cant log it can we?
return nil, err
}
if azureErr.Code != tableAlreadyExists {
// we are ok if the table already exists. Otherwise return nil
return nil, errors.New("Unable to create log table")
}
}
return table, nil
}
func createTableClient( accountName string, accountKey string ) (*storage.Client, error) {
// use parameters if passed in otherwise fall back to env vars.
if accountName == "" || accountKey == "" {
accountName = os.Getenv("ACCOUNT_NAME")
accountKey = os.Getenv("ACCOUNT_KEY")
}
client, err := storage.NewBasicClient(accountName, accountKey)
if err != nil {
return nil, err
}
return &client, nil
}
// Fire adds the logrus entry to Azure Table Storage
func (hook *AtsHook) Fire(entry *logrus.Entry) error {
rowKey := strconv.FormatInt(int64(entry.Time.UnixNano()), 10)
tableEntry := hook.table.GetEntityReference("logrus",rowKey )
props := make(map[string]interface{})
// technically dont need to make since entry.Data is already a map to interface. But will keep mapping here incase it changes.
for k,v := range entry.Data {
props[k] = v
}
props[timestampID] = entry.Time.UTC()
props[levelID] = entry.Level.String()
props[messageID] = entry.Message
tableEntry.Properties = props
err := tableEntry.Insert(storage.EmptyPayload, nil)
if err != nil {
return err
}
return nil
}
// Levels returns configured log levels
func (hook *AtsHook) Levels() []logrus.Level {
return hook.levels
}