Skip to content

Commit

Permalink
extconfig: make log_iml work correctly (#1310)
Browse files Browse the repository at this point in the history
  • Loading branch information
BeryJu authored Nov 23, 2024
1 parent 9bc6f9d commit e243211
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 122 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,15 @@ gen-client-ts:
cd ${PWD}/gen-ts-api && npm i
\cp -rf ${PWD}/gen-ts-api/* ${PWD}/web/node_modules/gravity-api

gen-client-ts-update: gen-client-ts
gen-client-ts-publish: gen-client-ts
cd ${PWD}/gen-ts-api
npm publish
cd ${PWD}/web
npm i gravity-api@${VERSION}
npm version ${VERSION} || true
git add package*.json

gen: gen-build gen-clean gen-client-go gen-client-ts-update gen-tag
gen: gen-build gen-clean gen-client-go gen-client-ts-publish gen-tag

lint: web-lint
golangci-lint run -v --timeout 5000s
Expand Down
6 changes: 3 additions & 3 deletions pkg/extconfig/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (e *ExtConfig) GetInterfaceForIP(forIp net.IP) (*net.Interface, error) {
for _, i := range ifaces {
addrs, err := e.checkInterface(i)
if err != nil {
e.Logger().Debug("failed to get IPs from interface", zap.Error(err), zap.String("if", i.Name))
e.intLog().Debug("failed to get IPs from interface", zap.Error(err), zap.String("if", i.Name))
continue
}
for _, addr := range addrs {
Expand All @@ -74,13 +74,13 @@ func (e *ExtConfig) GetIP() (net.IP, error) {
for _, i := range ifaces {
addrs, err := e.checkInterface(i)
if err != nil {
e.Logger().Debug("failed to get IPs from interface", zap.Error(err), zap.String("if", i.Name))
e.intLog().Debug("failed to get IPs from interface", zap.Error(err), zap.String("if", i.Name))
continue
}
if len(addrs) < 1 {
continue
}
e.Logger().Debug("Detected IP of instance", zap.String("ip", addrs[0].String()))
e.intLog().Debug("Detected IP of instance", zap.String("ip", addrs[0].String()))
return addrs[0], nil
}
return nil, errors.New("failed to find IP, set `INSTANCE_IP`")
Expand Down
8 changes: 6 additions & 2 deletions pkg/extconfig/log.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package extconfig

import (
_ "beryju.io/gravity/pkg/extconfig/log_iml"
"beryju.io/gravity/pkg/extconfig/log_iml"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
Expand All @@ -10,6 +10,10 @@ func (e *ExtConfig) Logger() *zap.Logger {
return e.logger
}

func (e *ExtConfig) intLog() *zap.Logger {
return e.Logger().Named("extconfig")
}

func (e *ExtConfig) BuildLogger() *zap.Logger {
l, err := zapcore.ParseLevel(e.LogLevel)
if err != nil {
Expand Down Expand Up @@ -45,5 +49,5 @@ func (e *ExtConfig) BuildLoggerWithLevel(l zapcore.Level) *zap.Logger {
return log.With(
zap.String("instance", e.Instance.Identifier),
zap.String("version", FullVersion()),
)
).WithOptions(log_iml.Get().Hook())
}
49 changes: 15 additions & 34 deletions pkg/extconfig/log_iml/log_iml.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,31 @@
package log_iml

import (
"bytes"
"net/url"
"strings"
"sync"

"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

type inMemoryLogger struct {
msgs []string
msgM sync.RWMutex
lineBuf *bytes.Buffer
max int
msgs []zapcore.Entry
msgM sync.RWMutex
max int
}

func (iml *inMemoryLogger) Close() error { return nil }
func (iml *inMemoryLogger) Sync() error { return nil }
func (iml *inMemoryLogger) flush() {
go func() {
func (iml *inMemoryLogger) Hook() zap.Option {
return zap.Hooks(func(e zapcore.Entry) error {
iml.msgM.Lock()
iml.msgs = append(iml.msgs, iml.lineBuf.String())
iml.lineBuf.Reset()
defer iml.msgM.Unlock()
iml.msgs = append(iml.msgs, e)
if len(iml.msgs) > iml.max {
iml.msgs = iml.msgs[1:]
}
iml.msgM.Unlock()
}()
}

func (iml *inMemoryLogger) Write(log []byte) (int, error) {
n, err := iml.lineBuf.Write(log)
if strings.Contains(string(log), "\n") {
iml.flush()
}
return n, err
return nil
})
}

func (iml *inMemoryLogger) Messages() []string {
func (iml *inMemoryLogger) Messages() []zapcore.Entry {
iml.msgM.RLock()
defer iml.msgM.RUnlock()
return iml.msgs
Expand All @@ -48,20 +35,14 @@ var iml *inMemoryLogger

func init() {
iml = &inMemoryLogger{
msgs: make([]string, 0),
max: 300,
lineBuf: new(bytes.Buffer),
}
err := zap.RegisterSink("gravity-in-memory", func(u *url.URL) (zap.Sink, error) {
return iml, nil
})
if err != nil {
panic(err)
msgs: make([]zapcore.Entry, 0),
max: 300,
}
}

type InMemoryLogger interface {
Messages() []string
Messages() []zapcore.Entry
Hook() zap.Option
}

func Get() InMemoryLogger {
Expand Down
16 changes: 11 additions & 5 deletions pkg/roles/api/api_cluster_node_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"context"
"time"

"beryju.io/gravity/pkg/extconfig"
"beryju.io/gravity/pkg/extconfig/log_iml"
Expand All @@ -10,21 +11,26 @@ import (
)

type APILogMessage struct {
Message string `json:"message"`
Node string `json:"node"`
Message string `json:"message"`
Time time.Time `json:"time"`
Level string `json:"level"`
Logger string `json:"logger"`

Node string `json:"node"`
}

type APILogMessages struct {
IsJSON bool `json:"isJSON"`
Messages []APILogMessage `json:"messages"`
}

func (r *Role) APIClusterNodeLogMessages() usecase.Interactor {
u := usecase.NewInteractor(func(ctx context.Context, input struct{}, output *APILogMessages) error {
output.IsJSON = !extconfig.Get().Debug
for _, lm := range log_iml.Get().Messages() {
output.Messages = append(output.Messages, APILogMessage{
Message: lm,
Message: lm.Message,
Level: lm.Level.CapitalString(),
Time: lm.Time,
Logger: lm.LoggerName,
Node: extconfig.Get().Instance.Identifier,
})
}
Expand Down
11 changes: 8 additions & 3 deletions schema.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
openapi: 3.0.3
info:
title: gravity
version: 0.14.0
version: 0.14.1
paths:
/api/v1/auth/config:
get:
Expand Down Expand Up @@ -1579,15 +1579,20 @@ components:
type: object
ApiAPILogMessage:
properties:
level:
type: string
logger:
type: string
message:
type: string
node:
type: string
time:
format: date-time
type: string
type: object
ApiAPILogMessages:
properties:
isJSON:
type: boolean
messages:
items:
$ref: '#/components/schemas/ApiAPILogMessage'
Expand Down
25 changes: 0 additions & 25 deletions web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
"@typescript-eslint/eslint-plugin": "^8.15.0",
"@typescript-eslint/parser": "^8.15.0",
"@webcomponents/webcomponentsjs": "^2.8.0",
"ansi-to-html": "^0.7.2",
"chart.js": "^4.4.6",
"chartjs-adapter-moment": "^1.0.1",
"codemirror": "^6.0.1",
Expand Down
63 changes: 16 additions & 47 deletions web/src/pages/cluster/ClusterNodeLogsPage.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import Convert from "ansi-to-html";
import { ApiAPILogMessage, RolesApiApi } from "gravity-api";

import { TemplateResult, html } from "lit";
import { customElement, state } from "lit/decorators.js";
import { unsafeHTML } from "lit/directives/unsafe-html.js";
import { customElement } from "lit/decorators.js";

import { DEFAULT_CONFIG } from "../../api/Config";
import "../../elements/PageHeader";
Expand All @@ -15,10 +13,6 @@ import { PaginationWrapper } from "../../utils";

@customElement("gravity-cluster-node-logs")
export class ClusterNodeLogsPage extends TablePage<ApiAPILogMessage> {
converter = new Convert();

@state()
isStructured = false;

pageTitle(): string {
return "Node logs";
Expand All @@ -31,54 +25,29 @@ export class ClusterNodeLogsPage extends TablePage<ApiAPILogMessage> {
}
async apiEndpoint(): Promise<PaginatedResponse<ApiAPILogMessage>> {
const logs = await new RolesApiApi(DEFAULT_CONFIG).apiGetLogMessages();
this.isStructured = logs.isJSON || true;
if (!logs.messages) {
logs.messages = [];
}
logs.messages.reverse();
return PaginationWrapper(logs.messages);
}
columns(): TableColumn[] {
if (this.isStructured) {
return [
new TableColumn("Level"),
new TableColumn("Timestamp"),
new TableColumn("Logger"),
new TableColumn("Message"),
new TableColumn("Fields"),
];
}
return [new TableColumn("Message")];
return [
new TableColumn("Level"),
new TableColumn("Timestamp"),
new TableColumn("Logger"),
new TableColumn("Message"),
new TableColumn("Fields"),
];
}

row(item: ApiAPILogMessage): TemplateResult[] {
if (this.isStructured) {
try {
const payload: LogMessage = JSON.parse(item.message || "");
const otherFields: { [key: string]: unknown } = { ...payload };
delete otherFields.level;
delete otherFields.logger;
delete otherFields.msg;
delete otherFields.ts;
return [
html`${payload.level}`,
html`${new Date(payload.ts * 1000).toLocaleTimeString()}`,
html`${payload.logger}`,
html`${payload.msg}`,
html`<pre>${JSON.stringify(otherFields)}</pre>`,
];
} catch (error) {
console.log(error);
this.isStructured = false;
}
}
return [html`${unsafeHTML(this.converter.toHtml(item.message || ""))}`];
return [
html`${item.level}`,
html`${item.time?.toLocaleString()}`,
html`<pre>${item.logger}</pre>`,
html`<pre>${item.message}</pre>`,
html``,
];
}
}

interface LogMessage {
level: string;
ts: number;
logger: string;
msg: string;
[key: string]: unknown;
}

0 comments on commit e243211

Please sign in to comment.