Skip to content

Commit

Permalink
feat(settings): basic log api and ui
Browse files Browse the repository at this point in the history
  • Loading branch information
lochstar committed Dec 16, 2020
1 parent d9788c4 commit 200085a
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 16 deletions.
35 changes: 35 additions & 0 deletions overseerr-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1419,6 +1419,41 @@ paths:
nextExecutionTime:
type: string
example: '2020-09-02T05:02:23.000Z'
/settings/logs:
get:
summary: Returns logs
description: Returns list of all log items and details
tags:
- settings
parameters:
- in: query
name: rows
schema:
type: number
example: 1000
default: 1000
responses:
'200':
description: Server log returned
content:
application/json:
schema:
type: array
items:
type: object
properties:
label:
type: string
example: SERVER
level:
type: string
example: info
message:
type: string
example: Server ready on port 3000
timestamp:
type: string
example: 2020-12-15T16:20:00.069Z
/settings/notifications/email:
get:
summary: Return current email notification settings
Expand Down
13 changes: 9 additions & 4 deletions server/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ const hformat = winston.format.printf(
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'debug',
format: winston.format.combine(
winston.format.colorize(),
winston.format.splat(),
winston.format.timestamp(),
hformat
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.splat(),
winston.format.timestamp(),
hformat
),
}),
new winston.transports.File({
filename: path.join(__dirname, '../config/logs/overseerr.log'),
}),
Expand Down
28 changes: 21 additions & 7 deletions server/routes/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ settingsRoutes.post('/main', (req, res) => {
return res.status(200).json(settings.main);
});

settingsRoutes.get('/plex', (_req, res) => {
settingsRoutes.get('/plex', (req, res) => {
const settings = getSettings();

res.status(200).json(settings.plex);
Expand Down Expand Up @@ -134,7 +134,7 @@ settingsRoutes.get('/plex/sync', (req, res) => {
return res.status(200).json(jobPlexFullSync.status());
});

settingsRoutes.get('/radarr', (_req, res) => {
settingsRoutes.get('/radarr', (req, res) => {
const settings = getSettings();

res.status(200).json(settings.radarr);
Expand Down Expand Up @@ -275,7 +275,7 @@ settingsRoutes.delete<{ id: string }>('/radarr/:id', (req, res) => {
return res.status(200).json(removed[0]);
});

settingsRoutes.get('/sonarr', (_req, res) => {
settingsRoutes.get('/sonarr', (req, res) => {
const settings = getSettings();

res.status(200).json(settings.sonarr);
Expand Down Expand Up @@ -386,7 +386,7 @@ settingsRoutes.delete<{ id: string }>('/sonarr/:id', (req, res) => {
return res.status(200).json(removed[0]);
});

settingsRoutes.get('/jobs', (_req, res) => {
settingsRoutes.get('/jobs', (req, res) => {
return res.status(200).json(
scheduledJobs.map((job) => ({
name: job.name,
Expand All @@ -395,10 +395,24 @@ settingsRoutes.get('/jobs', (_req, res) => {
);
});

settingsRoutes.get('/logs', (req, res) => {
const options = {
rows: Number(req.query.rows),
fields: null,
};

return logger.query(options, (err, results) => {
if (err) {
return res.status(500).json(err);
}
return res.status(200).json(results.file);
});
});

settingsRoutes.get(
'/initialize',
isAuthenticated(Permission.ADMIN),
(_req, res) => {
(req, res) => {
const settings = getSettings();

settings.public.initialized = true;
Expand All @@ -408,7 +422,7 @@ settingsRoutes.get(
}
);

settingsRoutes.get('/notifications/discord', (_req, res) => {
settingsRoutes.get('/notifications/discord', (req, res) => {
const settings = getSettings();

res.status(200).json(settings.notifications.agents.discord);
Expand All @@ -423,7 +437,7 @@ settingsRoutes.post('/notifications/discord', (req, res) => {
res.status(200).json(settings.notifications.agents.discord);
});

settingsRoutes.get('/notifications/email', (_req, res) => {
settingsRoutes.get('/notifications/email', (req, res) => {
const settings = getSettings();

res.status(200).json(settings.notifications.agents.email);
Expand Down
68 changes: 63 additions & 5 deletions src/components/Settings/SettingsLogs/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,72 @@
import React from 'react';
import useSWR from 'swr';
import Error from '../../../pages/_error';
import LoadingSpinner from '../../Common/LoadingSpinner';
import {
FormattedDate,
FormattedTime,
useIntl,
defineMessages,
} from 'react-intl';

// We will localize this file when the complete version is released.
const messages = defineMessages({
logs: 'Logs',
logsDescription:
'You can access your logs directly in stdout (container logs) or looking in /app/config/logs/overseerr.logs',
});

const SettingsLogs: React.FC = () => {
const intl = useIntl();
const { data, error } = useSWR('/api/v1/settings/logs');

if (error) {
return <Error statusCode={500} />;
}

if (!data && !error) {
return <LoadingSpinner />;
}

if (!data) {
return <LoadingSpinner />;
}

return (
<>
<div className="leading-loose text-gray-300 text-sm">
Logs page is still being built. For now, you can access your logs
directly in <code>stdout</code> (container logs) or looking in{' '}
<code>/app/config/logs/overseerr.logs</code>
<div>
<h3 className="text-lg leading-6 font-medium text-gray-200">
{intl.formatMessage(messages.logs)}
</h3>
<p className="text-sm leading-5 text-gray-500">
{intl.formatMessage(messages.logsDescription)}
</p>

<div className="mt-4 text-sm">
{data?.map((row, index) => (
<div key={`log-list-${index}`} className="space-x-2 text-gray-300">
<span className="inline">
<FormattedDate
value={row.timestamp}
year="numeric"
month="short"
day="2-digit"
/>
&nbsp;
<FormattedTime
value={row.timestamp}
hour="numeric"
minute="numeric"
second="numeric"
hour12={false}
/>
</span>
<span className="inline">
[{row.level}][{row.label}]:
</span>
<span className="inline">{row.message}</span>
</div>
))}
</div>
</div>
</>
);
Expand Down

0 comments on commit 200085a

Please sign in to comment.