Skip to content

Commit

Permalink
log UI
Browse files Browse the repository at this point in the history
  • Loading branch information
wardviaene committed Sep 20, 2024
1 parent e6c5b61 commit fdee5a4
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 32 deletions.
2 changes: 1 addition & 1 deletion pkg/observability/buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (o *Observability) WriteBufferToStorage(n int64) error {
func (o *Observability) monitorBuffer() {
for {
time.Sleep(FLUSH_TIME_MAX_MINUTES * time.Minute)
if time.Since(o.LastFlushed) >= (FLUSH_TIME_MAX_MINUTES * time.Minute) {
if time.Since(o.LastFlushed) >= (FLUSH_TIME_MAX_MINUTES*time.Minute) && o.Buffer.Len() > 0 {
if o.FlushOverflow.CompareAndSwap(false, true) {
err := o.WriteBufferToStorage(int64(o.Buffer.Len()))
o.FlushOverflow.Swap(true)
Expand Down
2 changes: 1 addition & 1 deletion pkg/observability/buffer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
func TestIngestion(t *testing.T) {
totalMessagesToGenerate := 1000
storage := &memorystorage.MockMemoryStorage{}
o := NewWithoutMonitor(20)
o := NewWithoutMonitor(storage, 20)
o.Storage = storage
payload := IncomingData{
{
Expand Down
2 changes: 2 additions & 0 deletions pkg/observability/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ package observability

const MAX_BUFFER_SIZE = 1024 * 1024 // 1 MB
const FLUSH_TIME_MAX_MINUTES = 5

const TIMESTAMP_FORMAT = "2006-01-02T15:04:05"
2 changes: 1 addition & 1 deletion pkg/observability/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

func TestIngestionHandler(t *testing.T) {
storage := &memorystorage.MockMemoryStorage{}
o := NewWithoutMonitor(20)
o := NewWithoutMonitor(storage, 20)
o.Storage = storage
payload := IncomingData{
{
Expand Down
12 changes: 11 additions & 1 deletion pkg/observability/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package observability
import (
"bufio"
"fmt"
"math"
"time"
)

Expand Down Expand Up @@ -44,8 +45,10 @@ func (o *Observability) getLogs(fromDate, endDate time.Time, pos int64, offset,
logMessage := decodeMessage(scanner.Bytes())
val, ok := logMessage.Data["log"]
if ok {
timestamp := floatToDate(logMessage.Date).Add(time.Duration(offset) * time.Minute)
logEntry := LogEntry{
Data: val,
Timestamp: timestamp.Format(TIMESTAMP_FORMAT),
Data: val,
}
logEntryResponse.LogEntries = append(logEntryResponse.LogEntries, logEntry)
}
Expand All @@ -57,3 +60,10 @@ func (o *Observability) getLogs(fromDate, endDate time.Time, pos int64, offset,

return logEntryResponse, nil
}

func floatToDate(datetime float64) time.Time {
datetimeInt := int64(datetime)
decimals := datetime - float64(datetimeInt)
nsecs := int64(math.Round(decimals * 1_000_000)) // precision to match golang's time.Time
return time.Unix(datetimeInt, nsecs*1000)
}
15 changes: 13 additions & 2 deletions pkg/observability/logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import (
func TestGetLogs(t *testing.T) {
totalMessagesToGenerate := 100
storage := &memorystorage.MockMemoryStorage{}
o := NewWithoutMonitor(20)
o.Storage = storage
o := NewWithoutMonitor(storage, 20)
payload := IncomingData{
{
"date": 1720613813.197045,
Expand Down Expand Up @@ -57,4 +56,16 @@ func TestGetLogs(t *testing.T) {
if len(logEntryResponse.LogEntries) != totalMessagesToGenerate {
t.Fatalf("didn't get the same log entries as messaged we generated: got: %d, expected: %d", len(logEntryResponse.LogEntries), totalMessagesToGenerate)
}
if logEntryResponse.LogEntries[0].Timestamp != floatToDate(1720613813.197045).Format(TIMESTAMP_FORMAT) {
t.Fatalf("unexpected timestamp")
}
}

func TestFloatToDate(t *testing.T) {
now := time.Now()
floatDate := float64(now.Unix()) + float64(now.Nanosecond())/1e9
floatToDate := floatToDate(floatDate)
if !now.Equal(floatToDate) {
t.Fatalf("times are not equal. Got: %s, expected: %s", floatToDate, now)
}
}
9 changes: 6 additions & 3 deletions pkg/observability/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ package observability

import (
"net/http"

"github.com/in4it/wireguard-server/pkg/storage"
)

func New() *Observability {
o := NewWithoutMonitor(MAX_BUFFER_SIZE)
func New(storage storage.Iface) *Observability {
o := NewWithoutMonitor(storage, MAX_BUFFER_SIZE)
go o.monitorBuffer()
return o
}
func NewWithoutMonitor(maxBufferSize int) *Observability {
func NewWithoutMonitor(storage storage.Iface, maxBufferSize int) *Observability {
o := &Observability{
Buffer: &ConcurrentRWBuffer{},
MaxBufferSize: maxBufferSize,
Storage: storage,
}
return o
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/rest/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ func newContext(storage storage.Iface, serverType string) (*Context, error) {

if c.Observability == nil {
c.Observability = &Observability{
Client: observability.New(),
Client: observability.New(storage),
}
} else {
c.Observability.Client = observability.New()
c.Observability.Client = observability.New(storage)
}

return c, nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/rest/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func (c *Context) contextHandler(w http.ResponseWriter, r *http.Request) {
}
}

out, err := json.Marshal(ContextSetupResponse{SetupCompleted: c.SetupCompleted, CloudType: c.CloudType})
out, err := json.Marshal(ContextSetupResponse{SetupCompleted: c.SetupCompleted, CloudType: c.CloudType, ServerType: c.ServerType})
if err != nil {
c.returnError(w, err, http.StatusBadRequest)
return
Expand Down
1 change: 1 addition & 0 deletions pkg/rest/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ type ContextRequest struct {
type ContextSetupResponse struct {
SetupCompleted bool `json:"setupCompleted"`
CloudType string `json:"cloudType"`
ServerType string `json:"serverType"`
}

type AuthMethodsResponse struct {
Expand Down
37 changes: 35 additions & 2 deletions webapp/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Profile } from "./Routes/Profile/Profile";
import { Upgrade } from "./Routes/Upgrade/Upgrade";
import { GetMoreLicenses } from "./Routes/Licenses/GetMoreLicenses";
import { PacketLogs } from "./Routes/PacketLogs/PacketLogs";
import { Logs } from "./Routes/Logs/Logs";

const queryClient = new QueryClient()

Expand All @@ -27,7 +28,7 @@ export default function App() {
return <MantineProvider theme={theme} forceColorScheme="light">
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppInit>
<AppInit serverType="vpn">
<Auth>
<AppShell
navbar={{
Expand All @@ -38,7 +39,7 @@ export default function App() {
padding="md"
>
<AppShell.Navbar>
<NavBar />
<NavBar serverType="vpn" />
</AppShell.Navbar>
<AppShell.Main>
<Routes>
Expand All @@ -60,6 +61,38 @@ export default function App() {
</AppShell>
</Auth>
</AppInit>
<AppInit serverType="observability">
<Auth>
<AppShell
navbar={{
width: 300,
breakpoint: 'sm',
collapsed: { mobile: opened },
}}
padding="md"
>
<AppShell.Navbar>
<NavBar serverType="observability" />
</AppShell.Navbar>
<AppShell.Main>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/users" element={<CheckRole role="admin"><Users /></CheckRole>} />
<Route path="/setup" element={<CheckRole role="admin"><Setup /></CheckRole>} />
<Route path="/setup/:page" element={<CheckRole role="admin"><Setup /></CheckRole>} />
<Route path="/auth-setup" element={<CheckRole role="admin"><AuthSetup /></CheckRole>} />
<Route path="/upgrade" element={<CheckRole role="admin"><Upgrade /></CheckRole>} />
<Route path="/licenses" element={<CheckRole role="admin"><GetMoreLicenses /></CheckRole>} />
<Route path="/logs" element={<Logs />} />
<Route path="/logout" element={<Logout />} />
<Route path="/login/:logintype/:id" element={<Navigate to={"/"} />} />
<Route path="/callback/:callbacktype/:id" element={<Navigate to={"/"} />} />
<Route path="/profile" element={<Profile />} />
</Routes>
</AppShell.Main>
</AppShell>
</Auth>
</AppInit>
</BrowserRouter>
</QueryClientProvider>
</MantineProvider>;
Expand Down
14 changes: 10 additions & 4 deletions webapp/src/AppInit/AppInit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import React, { useState } from 'react';
import { SetupBanner } from './SetupBanner';
import { AppSettings } from '../Constants/Constants';

type Props = {
children?: React.ReactNode
};

export const AppInit: React.FC<Props> = ({children}) => {
type Props = {
children?: React.ReactNode
serverType: string
};

export const AppInit: React.FC<Props> = ({children, serverType}) => {
const [setupCompleted, setSetupCompleted] = useState<boolean>(false);
const { isPending, error, data } = useQuery({
queryKey: ['context'],
Expand All @@ -22,6 +24,10 @@ import { AppSettings } from '../Constants/Constants';
if (isPending) return ''
if (error) return 'An backend error has occurred: ' + error.message

if (data.serverType !== serverType) {
return ''
}

if(!setupCompleted && data.setupCompleted) {
setSetupCompleted(true)
}
Expand Down
69 changes: 55 additions & 14 deletions webapp/src/NavBar/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,66 @@ import { NavLink, useLocation } from 'react-router-dom';
import { useAuthContext } from '../Auth/Auth';
import { Version } from './Version';

export function NavBar() {
type Props = {
serverType: string
};


export function NavBar({serverType}: Props) {
const {authInfo} = useAuthContext();
const location = useLocation();
const { pathname } = location;
const [active, setActive] = useState(pathname);

const data = authInfo.role === "admin" ? [
{ link: '/', label: 'Status', icon: TbBellRinging },
{ link: '/connection', label: 'VPN Connections', icon: TbPlugConnected },
{ link: '/users', label: 'Users', icon: TbUser },
{ link: '/setup', label: 'VPN Setup', icon: TbSettings },
{ link: '/auth-setup', label: 'Authentication & Provisioning', icon: TbCloudDataConnection },
{ link: '/packetlogs', label: 'Logging', icon: FaStream },
{ link: 'https://vpn-documentation.in4it.com', label: 'Documentation', icon: TbBook },
] :
[
{ link: '/connection', label: 'VPN Connections', icon: TbPlugConnected },
{ link: 'https://vpn-documentation.in4it.com', label: 'Documentation', icon: TbBook },
];
const vpnLinks = {
"admin": [
{ link: '/', label: 'Status', icon: TbBellRinging },
{ link: '/connection', label: 'VPN Connections', icon: TbPlugConnected },
{ link: '/users', label: 'Users', icon: TbUser },
{ link: '/setup', label: 'VPN Setup', icon: TbSettings },
{ link: '/auth-setup', label: 'Authentication & Provisioning', icon: TbCloudDataConnection },
{ link: '/packetlogs', label: 'Logging', icon: FaStream },
{ link: 'https://vpn-documentation.in4it.com', label: 'Documentation', icon: TbBook },
],
"user": [
{ link: '/connection', label: 'VPN Connections', icon: TbPlugConnected },
{ link: 'https://vpn-documentation.in4it.com', label: 'Documentation', icon: TbBook },
]
}
const observabilityLinks = {
"admin": [
{ link: '/', label: 'Status', icon: TbBellRinging },
{ link: '/users', label: 'Users', icon: TbUser },
{ link: '/setup', label: 'VPN Setup', icon: TbSettings },
{ link: '/auth-setup', label: 'Authentication & Provisioning', icon: TbCloudDataConnection },
{ link: '/logs', label: 'Logs', icon: FaStream },
{ link: 'https://vpn-documentation.in4it.com', label: 'Documentation', icon: TbBook },
],
"user": [
{ link: '/logs', label: 'Logs', icon: FaStream },
{ link: 'https://vpn-documentation.in4it.com', label: 'Documentation', icon: TbBook },
]
}

const getData = () => {
if(serverType === "vpn") {
if (authInfo.role === "admin" ) {
return vpnLinks.admin
} else {
return vpnLinks.user
}
}
if(serverType === "observability") {
if (authInfo.role === "admin" ) {
return observabilityLinks.admin
} else {
return observabilityLinks.user
}
}
return []
}

const data = getData()

const links = data.map((item) => (
<NavLink
Expand Down

0 comments on commit fdee5a4

Please sign in to comment.