summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2021-10-02 10:46:47 +0300
committerPaul Buetow <paul@buetow.org>2021-10-02 12:26:36 +0300
commit764ef99a3d779a0db1fb60679292af52425ba2f6 (patch)
tree2547b3bd4472a4178173dfe1d8f4178af591c37e /internal
parent609921f9c783941eaa9019a92b78ec45b49d681c (diff)
add more default fields to MAPREDUCE
Diffstat (limited to 'internal')
-rw-r--r--internal/config/args.go2
-rw-r--r--internal/config/config.go1
-rw-r--r--internal/io/dlog/dlog.go38
-rw-r--r--internal/io/dlog/loggers/file.go1
-rw-r--r--internal/mapr/logformat/default.go23
-rw-r--r--internal/mapr/logformat/default_test.go62
-rw-r--r--internal/server/stats.go4
7 files changed, 108 insertions, 23 deletions
diff --git a/internal/config/args.go b/internal/config/args.go
index 7f24348..484aa8b 100644
--- a/internal/config/args.go
+++ b/internal/config/args.go
@@ -39,7 +39,7 @@ func (a *Args) String() string {
var sb strings.Builder
sb.WriteString("Args(")
- // TODO: All commands should make use of this
+
sb.WriteString(fmt.Sprintf("%s:%s,", "LogDir", a.LogDir))
sb.WriteString(fmt.Sprintf("%s:%s,", "LogLevel", a.LogLevel))
sb.WriteString(fmt.Sprintf("%s:%v,", "Arguments", a.Arguments))
diff --git a/internal/config/config.go b/internal/config/config.go
index 76dcc65..3d05a11 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -85,7 +85,6 @@ func (c *configInitializer) transformConfig(args *Args, additionalArgs []string,
if args.LogDir != "" {
common.LogDir = args.LogDir
if common.LogStrategy == "" {
- // TODO: Implement the other (not-daily) log strategy for the server.
common.LogStrategy = "daily"
}
}
diff --git a/internal/io/dlog/dlog.go b/internal/io/dlog/dlog.go
index 49533a5..bc9b2f8 100644
--- a/internal/io/dlog/dlog.go
+++ b/internal/io/dlog/dlog.go
@@ -3,7 +3,11 @@ package dlog
import (
"context"
"fmt"
+ "io/ioutil"
"os"
+ "path/filepath"
+ "runtime"
+ "strconv"
"strings"
"sync"
"time"
@@ -211,8 +215,38 @@ func (d *DLog) Raw(message string) string {
func (d *DLog) Mapreduce(table string, data map[string]interface{}) string {
args := make([]interface{}, len(data)+1)
- // TODO: mC compatible SERVER mapreduce fields, no MAPREDUCE keyword in CLIENT mode
- args[0] = fmt.Sprintf("%s:%s", "MAPREDUCE", strings.ToUpper(table))
+ if d.sourceProcess == SERVER {
+ // level|date-time|process|caller|cpus|goroutines|cgocalls|loadavg|uptime|MAPREDUCE:TABLE|key=value|...
+
+ var loadAvg string
+ if loadAvgBytes, err := ioutil.ReadFile("/proc/loadavg"); err == nil {
+ tmp := string(loadAvgBytes)
+ s := strings.SplitN(tmp, " ", 2)
+ loadAvg = s[0]
+ }
+
+ var uptime string
+ if uptimeBytes, err := ioutil.ReadFile("/proc/uptime"); err == nil {
+ tmp := string(uptimeBytes)
+ s := strings.SplitN(tmp, ".", 2)
+ i, _ := strconv.ParseInt(s[0], 10, 64)
+ t := time.Duration(i) * time.Second
+ uptime = fmt.Sprintf("%v", t)
+ }
+
+ _, file, line, _ := runtime.Caller(1)
+ args[0] = fmt.Sprintf("%d|%s:%d|%d|%d|%d|%s|%s|MAPREDUCE:%s",
+ os.Getpid(),
+ filepath.Base(file), line,
+ runtime.NumCPU(),
+ runtime.NumGoroutine(),
+ runtime.NumCgoCall(),
+ loadAvg,
+ uptime,
+ strings.ToUpper(table))
+ } else {
+ args[0] = fmt.Sprintf("STATS:%s", strings.ToUpper(table))
+ }
i := 1
for k, v := range data {
diff --git a/internal/io/dlog/loggers/file.go b/internal/io/dlog/loggers/file.go
index dcdd7d0..6e692a3 100644
--- a/internal/io/dlog/loggers/file.go
+++ b/internal/io/dlog/loggers/file.go
@@ -100,7 +100,6 @@ func (f *file) Pause() { f.pauseCh <- struct{}{} }
func (f *file) Resume() { f.resumeCh <- struct{}{} }
func (f *file) Flush() { f.flushCh <- struct{}{} }
-// TODO: Test that Rotate() actually works.
func (f *file) Rotate() { f.rotateCh <- struct{}{} }
func (*file) SupportsColors() bool { return false }
diff --git a/internal/mapr/logformat/default.go b/internal/mapr/logformat/default.go
index 7fb1700..8016667 100644
--- a/internal/mapr/logformat/default.go
+++ b/internal/mapr/logformat/default.go
@@ -11,7 +11,7 @@ import (
func (p *Parser) MakeFieldsDEFAULT(maprLine string) (map[string]string, error) {
splitted := strings.Split(maprLine, protocol.FieldDelimiter)
- if len(splitted) < 3 || !strings.HasPrefix(splitted[3], "MAPREDUCE:") || !strings.HasPrefix(splitted[0], "INFO") {
+ if len(splitted) < 11 || !strings.HasPrefix(splitted[9], "MAPREDUCE:") || !strings.HasPrefix(splitted[0], "INFO") {
// Not a DTail mapreduce log line.
return nil, IgnoreFieldsErr
}
@@ -27,10 +27,25 @@ func (p *Parser) MakeFieldsDEFAULT(maprLine string) (map[string]string, error) {
fields["$severity"] = splitted[0]
fields["$loglevel"] = splitted[0]
- // NEXT: Parse time like we do at Mimecast
- fields["$time"] = splitted[1]
- for _, kv := range splitted[4:] {
+ time := splitted[1]
+ fields["$time"] = time
+ if len(time) == 15 {
+ // Example: 20211002-071209
+ fields["$date"] = time[0:8]
+ fields["$hour"] = time[9:11]
+ fields["$minute"] = time[11:13]
+ fields["$second"] = time[13:]
+ }
+ fields["$pid"] = splitted[2]
+ fields["$caller"] = splitted[3]
+ fields["$cpus"] = splitted[4]
+ fields["$goroutines"] = splitted[5]
+ fields["$cgocalls"] = splitted[6]
+ fields["$loadavg"] = splitted[7]
+ fields["$uptime"] = splitted[8]
+
+ for _, kv := range splitted[10:] {
keyAndValue := strings.SplitN(kv, "=", 2)
if len(keyAndValue) != 2 {
return fields, fmt.Errorf("Unable to parse key-value token '%s'", kv)
diff --git a/internal/mapr/logformat/default_test.go b/internal/mapr/logformat/default_test.go
index 79911d1..02c03a3 100644
--- a/internal/mapr/logformat/default_test.go
+++ b/internal/mapr/logformat/default_test.go
@@ -1,6 +1,7 @@
package logformat
import (
+ "fmt"
"testing"
)
@@ -10,9 +11,15 @@ func TestDefaultLogFormat(t *testing.T) {
t.Errorf("Unable to create parser: %s", err.Error())
}
+ date := "20211002"
+ hour := "07"
+ minute := "23"
+ second := "42"
+ time := fmt.Sprintf("%s-%s%s%s", date, hour, minute, second)
+
inputs := []string{
- "INFO|20210907-065632|SERVER|MAPREDUCE:TEST|foo=bar|baz=bay",
- "INFO|20210907-065732|CLIENT|MAPREDUCE:YOMAN|baz=bay|foo=bar",
+ fmt.Sprintf("INFO|%s|1|default_test.go:0|8|14|7|0.21|471h0m21s|MAPREDUCE:STATS|foo=bar|bar=foo", time),
+ fmt.Sprintf("INFO|%s|1|default_test.go:0|8|14|7|0.21|471h0m21s|MAPREDUCE:STATS|bar=foo|foo=bar", time),
}
for _, input := range inputs {
@@ -22,18 +29,53 @@ func TestDefaultLogFormat(t *testing.T) {
t.Errorf("Parser unable to make fields: %s", err.Error())
}
- if bar, ok := fields["foo"]; !ok {
- t.Errorf("Expected field 'foo', but no such field there in '%s'\n", input)
- } else if bar != "bar" {
- t.Errorf("Expected 'bar' stored in field 'foo', but got '%s' in '%s'\n", bar, input)
+ if val, ok := fields["$severity"]; !ok {
+ t.Errorf("Expected field '$severity', but no such field there in '%s'\n", input)
+ } else if val != "INFO" {
+ t.Errorf("Expected 'INFO' stored in field '$severity', but got '%s' in '%s'\n", val, input)
+ }
+
+ if val, ok := fields["$time"]; !ok {
+ t.Errorf("Expected field '$time', but no such field there in '%s'\n", input)
+ } else if val != time {
+ t.Errorf("Expected '%s' stored in field '$time', but got '%s' in '%s'\n", time, val, input)
+ }
+
+ if val, ok := fields["$date"]; !ok {
+ t.Errorf("Expected field '$date', but no such field there in '%s'\n", input)
+ } else if val != date {
+ t.Errorf("Expected '%s' stored in field '$date', but got '%s' in '%s'\n", date, val, input)
+ }
+
+ if val, ok := fields["$hour"]; !ok {
+ t.Errorf("Expected field '$hour', but no such field there in '%s'\n", input)
+ } else if val != hour {
+ t.Errorf("Expected '%s' stored in field '$hour', but got '%s' in '%s'\n", hour, val, input)
+ }
+
+ if val, ok := fields["$minute"]; !ok {
+ t.Errorf("Expected field '$minute', but no such field there in '%s'\n", input)
+ } else if val != minute {
+ t.Errorf("Expected '%s' stored in field '$minute', but got '%s' in '%s'\n", minute, val, input)
}
- if bay, ok := fields["baz"]; !ok {
- t.Errorf("Expected field 'baz', but no such field there in '%s'\n", input)
- } else if bay != "bay" {
- t.Errorf("Expected 'bay' stored in field 'baz', but got '%s' in '%s'\n", bay, input)
+ if val, ok := fields["$second"]; !ok {
+ t.Errorf("Expected field '$second', but no such field there in '%s'\n", input)
+ } else if val != second {
+ t.Errorf("Expected '%s' stored in field '$second', but got '%s' in '%s'\n", second, val, input)
}
+ if val, ok := fields["foo"]; !ok {
+ t.Errorf("Expected field 'foo', but no such field there in '%s'\n", input)
+ } else if val != "bar" {
+ t.Errorf("Expected 'bar' stored in field 'foo', but got '%s' in '%s'\n", val, input)
+ }
+
+ if val, ok := fields["bar"]; !ok {
+ t.Errorf("Expected field 'bar', but no such field there in '%s'\n", input)
+ } else if val != "foo" {
+ t.Errorf("Expected 'foo' stored in field 'bar', but got '%s' in '%s'\n", val, input)
+ }
}
fields, err := parser.MakeFields("foozoo=bar|bazbay")
diff --git a/internal/server/stats.go b/internal/server/stats.go
index 8583318..c07634d 100644
--- a/internal/server/stats.go
+++ b/internal/server/stats.go
@@ -3,7 +3,6 @@ package server
import (
"context"
"fmt"
- "runtime"
"sync"
"time"
@@ -53,9 +52,6 @@ func (s *stats) logServerStats() {
data := make(map[string]interface{})
data["currentConnections"] = s.currentConnections
data["lifetimeConnections"] = s.lifetimeConnections
- data["goroutines"] = runtime.NumGoroutine()
- data["cgocalls"] = runtime.NumCgoCall()
- data["cpu"] = runtime.NumCPU()
dlog.Server.Mapreduce("STATS", data)
}