mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
add max messages and make web log dynamic - #71
This commit is contained in:
@@ -6,6 +6,8 @@ import { useWindowSize } from '../components';
|
|||||||
|
|
||||||
interface LogEventConsoleProps {
|
interface LogEventConsoleProps {
|
||||||
events: LogEvent[];
|
events: LogEvent[];
|
||||||
|
compact: boolean;
|
||||||
|
level: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Offsets {
|
interface Offsets {
|
||||||
@@ -63,7 +65,9 @@ const useStyles = makeStyles((theme: Theme) => ({
|
|||||||
const LogEventConsole: FC<LogEventConsoleProps> = (props) => {
|
const LogEventConsole: FC<LogEventConsoleProps> = (props) => {
|
||||||
useWindowSize();
|
useWindowSize();
|
||||||
const classes = useStyles({ topOffset, leftOffset });
|
const classes = useStyles({ topOffset, leftOffset });
|
||||||
const { events } = props;
|
const { events, compact, level } = props;
|
||||||
|
|
||||||
|
const filter_events = events.filter((e) => e.l <= level);
|
||||||
|
|
||||||
const styleLevel = (level: LogLevel) => {
|
const styleLevel = (level: LogLevel) => {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
@@ -103,29 +107,34 @@ const LogEventConsole: FC<LogEventConsoleProps> = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const paddedLevelLabel = (level: LogLevel) => {
|
const paddedLevelLabel = (level: LogLevel, compact: boolean) => {
|
||||||
const label = levelLabel(level);
|
const label = levelLabel(level);
|
||||||
return label.padStart(8, '\xa0');
|
return compact ? ' ' + label[0] : label.padStart(8, '\xa0');
|
||||||
};
|
};
|
||||||
|
|
||||||
const paddedNameLabel = (name: string) => {
|
const paddedNameLabel = (name: string, compact: boolean) => {
|
||||||
const label = '[' + name + ']';
|
const label = '[' + name + ']';
|
||||||
return label.padEnd(12, '\xa0');
|
return compact ? label : label.padEnd(12, '\xa0');
|
||||||
};
|
};
|
||||||
|
|
||||||
const paddedIDLabel = (id: number) => {
|
const paddedIDLabel = (id: number, compact: boolean) => {
|
||||||
const label = id + ':';
|
const label = id + ':';
|
||||||
return label.padEnd(7, '\xa0');
|
return compact ? label : label.padEnd(7, '\xa0');
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box id="log-window" className={classes.console}>
|
<Box id="log-window" className={classes.console}>
|
||||||
{events.map((e) => (
|
{filter_events.map((e) => (
|
||||||
<div className={classes.entry} key={e.i}>
|
<div className={classes.entry} key={e.i}>
|
||||||
<span>{e.t}</span>
|
<span>{e.t}</span>
|
||||||
<span className={styleLevel(e.l)}>{paddedLevelLabel(e.l)} </span>
|
{compact && <span>{paddedLevelLabel(e.l, compact)} </span>}
|
||||||
<span>{paddedIDLabel(e.i)} </span>
|
{!compact && (
|
||||||
<span>{paddedNameLabel(e.n)} </span>
|
<span className={styleLevel(e.l)}>
|
||||||
|
{paddedLevelLabel(e.l, compact)}{' '}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span>{paddedIDLabel(e.i, compact)} </span>
|
||||||
|
<span>{paddedNameLabel(e.n, compact)} </span>
|
||||||
<span>{e.m}</span>
|
<span>{e.m}</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -3,19 +3,27 @@ import { Component } from 'react';
|
|||||||
import {
|
import {
|
||||||
restController,
|
restController,
|
||||||
RestControllerProps,
|
RestControllerProps,
|
||||||
RestFormLoader,
|
SectionContent,
|
||||||
SectionContent
|
BlockFormControlLabel
|
||||||
} from '../components';
|
} from '../components';
|
||||||
|
|
||||||
import { addAccessTokenParameter } from '../authentication';
|
import {
|
||||||
|
ValidatorForm,
|
||||||
|
SelectValidator
|
||||||
|
} from 'react-material-ui-form-validator';
|
||||||
|
|
||||||
|
import { Grid, Slider, FormLabel, Checkbox, MenuItem } from '@material-ui/core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
addAccessTokenParameter,
|
||||||
|
redirectingAuthorizedFetch
|
||||||
|
} from '../authentication';
|
||||||
|
|
||||||
import { ENDPOINT_ROOT, EVENT_SOURCE_ROOT } from '../api';
|
import { ENDPOINT_ROOT, EVENT_SOURCE_ROOT } from '../api';
|
||||||
export const FETCH_LOG_ENDPOINT = ENDPOINT_ROOT + 'fetchLog';
|
export const FETCH_LOG_ENDPOINT = ENDPOINT_ROOT + 'fetchLog';
|
||||||
export const LOG_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'logSettings';
|
export const LOG_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'logSettings';
|
||||||
|
|
||||||
export const LOG_EVENT_EVENT_SOURCE_URL = EVENT_SOURCE_ROOT + 'log';
|
export const LOG_EVENT_EVENT_SOURCE_URL = EVENT_SOURCE_ROOT + 'log';
|
||||||
|
|
||||||
import LogEventForm from './LogEventForm';
|
|
||||||
import LogEventConsole from './LogEventConsole';
|
import LogEventConsole from './LogEventConsole';
|
||||||
|
|
||||||
import { LogEvent, LogSettings } from './types';
|
import { LogEvent, LogSettings } from './types';
|
||||||
@@ -26,6 +34,9 @@ const decoder = new Decoder();
|
|||||||
interface LogEventControllerState {
|
interface LogEventControllerState {
|
||||||
eventSource?: EventSource;
|
eventSource?: EventSource;
|
||||||
events: LogEvent[];
|
events: LogEvent[];
|
||||||
|
compact: boolean;
|
||||||
|
level: number;
|
||||||
|
max_messages: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogEventControllerProps = RestControllerProps<LogSettings>;
|
type LogEventControllerProps = RestControllerProps<LogSettings>;
|
||||||
@@ -40,12 +51,15 @@ class LogEventController extends Component<
|
|||||||
constructor(props: LogEventControllerProps) {
|
constructor(props: LogEventControllerProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
events: []
|
events: [],
|
||||||
|
compact: false,
|
||||||
|
level: 6,
|
||||||
|
max_messages: 25
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.loadData();
|
this.fetchValues();
|
||||||
this.fetchLog();
|
this.fetchLog();
|
||||||
this.configureEventSource();
|
this.configureEventSource();
|
||||||
}
|
}
|
||||||
@@ -59,6 +73,15 @@ class LogEventController extends Component<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeCompact = (
|
||||||
|
event: React.ChangeEvent<HTMLInputElement>,
|
||||||
|
checked: boolean
|
||||||
|
) => {
|
||||||
|
this.setState({
|
||||||
|
compact: checked
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
fetchLog = () => {
|
fetchLog = () => {
|
||||||
fetch(FETCH_LOG_ENDPOINT)
|
fetch(FETCH_LOG_ENDPOINT)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@@ -78,6 +101,25 @@ class LogEventController extends Component<
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fetchValues = () => {
|
||||||
|
redirectingAuthorizedFetch(LOG_SETTINGS_ENDPOINT)
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
throw Error('Unexpected status code: ' + response.status);
|
||||||
|
})
|
||||||
|
.then((json) => {
|
||||||
|
this.setState({ level: json.level, max_messages: json.max_messages });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
const errorMessage = error.message || 'Unknown error';
|
||||||
|
this.props.enqueueSnackbar('Problem fetching: ' + errorMessage, {
|
||||||
|
variant: 'error'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
configureEventSource = () => {
|
configureEventSource = () => {
|
||||||
this.eventSource = new EventSource(
|
this.eventSource = new EventSource(
|
||||||
addAccessTokenParameter(LOG_EVENT_EVENT_SOURCE_URL)
|
addAccessTokenParameter(LOG_EVENT_EVENT_SOURCE_URL)
|
||||||
@@ -102,14 +144,114 @@ class LogEventController extends Component<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
changeMaxMessages = (
|
||||||
|
event: React.ChangeEvent<{}>,
|
||||||
|
value: number | number[]
|
||||||
|
) => {
|
||||||
|
this.setState({
|
||||||
|
max_messages: value as number
|
||||||
|
});
|
||||||
|
this.send_data(this.state.level, value as number);
|
||||||
|
};
|
||||||
|
|
||||||
|
changeLevel = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
this.setState({
|
||||||
|
level: parseInt(event.target.value)
|
||||||
|
});
|
||||||
|
this.send_data(parseInt(event.target.value), this.state.max_messages);
|
||||||
|
};
|
||||||
|
|
||||||
|
send_data = (level: number, max_messages: number) => {
|
||||||
|
redirectingAuthorizedFetch(LOG_SETTINGS_ENDPOINT, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
level: level,
|
||||||
|
max_messages: max_messages
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw Error('Unexpected response code: ' + response.status);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.props.enqueueSnackbar(
|
||||||
|
error.message || 'Problem applying log settings',
|
||||||
|
{ variant: 'warning' }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { saveData } = this.props;
|
||||||
return (
|
return (
|
||||||
<SectionContent title="System Log" id="log-window">
|
<SectionContent title="System Log" id="log-window">
|
||||||
<RestFormLoader
|
<ValidatorForm onSubmit={saveData}>
|
||||||
{...this.props}
|
<Grid
|
||||||
render={(formProps) => <LogEventForm {...formProps} />}
|
container
|
||||||
|
spacing={3}
|
||||||
|
direction="row"
|
||||||
|
justify="flex-start"
|
||||||
|
alignItems="center"
|
||||||
|
>
|
||||||
|
<Grid item xs={2}>
|
||||||
|
<SelectValidator
|
||||||
|
name="level"
|
||||||
|
label="Log Level"
|
||||||
|
value={this.state.level}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
onChange={this.changeLevel}
|
||||||
|
margin="normal"
|
||||||
|
>
|
||||||
|
<MenuItem value={3}>ERROR</MenuItem>
|
||||||
|
<MenuItem value={4}>WARNING</MenuItem>
|
||||||
|
<MenuItem value={5}>NOTICE</MenuItem>
|
||||||
|
<MenuItem value={6}>INFO</MenuItem>
|
||||||
|
<MenuItem value={7}>DEBUG</MenuItem>
|
||||||
|
<MenuItem value={8}>ALL</MenuItem>
|
||||||
|
</SelectValidator>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={2}>
|
||||||
|
<FormLabel>Buffer size</FormLabel>
|
||||||
|
<Slider
|
||||||
|
value={this.state.max_messages}
|
||||||
|
valueLabelDisplay="auto"
|
||||||
|
name="max_messages"
|
||||||
|
marks={[
|
||||||
|
{ value: 25, label: '25' },
|
||||||
|
{ value: 50, label: '50' },
|
||||||
|
{ value: 75, label: '75' }
|
||||||
|
]}
|
||||||
|
step={25}
|
||||||
|
min={25}
|
||||||
|
max={75}
|
||||||
|
onChange={this.changeMaxMessages}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={this.state.compact}
|
||||||
|
onChange={this.changeCompact}
|
||||||
|
value="compact"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Compact Layout"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</ValidatorForm>
|
||||||
|
|
||||||
|
<LogEventConsole
|
||||||
|
level={this.state.level}
|
||||||
|
compact={this.state.compact}
|
||||||
|
events={this.state.events}
|
||||||
/>
|
/>
|
||||||
<LogEventConsole events={this.state.events} />
|
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
import { Component } from 'react';
|
|
||||||
|
|
||||||
import {
|
|
||||||
ValidatorForm,
|
|
||||||
SelectValidator
|
|
||||||
} from 'react-material-ui-form-validator';
|
|
||||||
|
|
||||||
import { Typography, Grid } from '@material-ui/core';
|
|
||||||
|
|
||||||
import MenuItem from '@material-ui/core/MenuItem';
|
|
||||||
|
|
||||||
import {
|
|
||||||
redirectingAuthorizedFetch,
|
|
||||||
withAuthenticatedContext,
|
|
||||||
AuthenticatedContextProps
|
|
||||||
} from '../authentication';
|
|
||||||
|
|
||||||
import { RestFormProps } from '../components';
|
|
||||||
import { LogSettings } from './types';
|
|
||||||
|
|
||||||
import { ENDPOINT_ROOT } from '../api';
|
|
||||||
export const LOG_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'logSettings';
|
|
||||||
|
|
||||||
type LogEventFormProps = AuthenticatedContextProps & RestFormProps<LogSettings>;
|
|
||||||
|
|
||||||
class LogEventForm extends Component<LogEventFormProps> {
|
|
||||||
changeLevel = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
||||||
const { data, setData } = this.props;
|
|
||||||
setData({
|
|
||||||
...data,
|
|
||||||
level: parseInt(event.target.value)
|
|
||||||
});
|
|
||||||
|
|
||||||
redirectingAuthorizedFetch(LOG_SETTINGS_ENDPOINT, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({ level: event.target.value }),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
if (response.status === 200) {
|
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
throw Error('Unexpected response code: ' + response.status);
|
|
||||||
})
|
|
||||||
.then((json) => {
|
|
||||||
this.props.enqueueSnackbar('Log settings changed', {
|
|
||||||
variant: 'success'
|
|
||||||
});
|
|
||||||
setData({
|
|
||||||
...data,
|
|
||||||
level: json.level
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.props.enqueueSnackbar(
|
|
||||||
error.message || 'Problem changing log settings',
|
|
||||||
{ variant: 'warning' }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { data, saveData } = this.props;
|
|
||||||
return (
|
|
||||||
<ValidatorForm onSubmit={saveData}>
|
|
||||||
<Grid
|
|
||||||
container
|
|
||||||
direction="row"
|
|
||||||
justify="flex-start"
|
|
||||||
alignItems="center"
|
|
||||||
>
|
|
||||||
<Grid item xs={2}>
|
|
||||||
<SelectValidator
|
|
||||||
name="level"
|
|
||||||
label="Filter on Log Level"
|
|
||||||
value={data.level}
|
|
||||||
fullWidth
|
|
||||||
variant="outlined"
|
|
||||||
onChange={this.changeLevel}
|
|
||||||
margin="normal"
|
|
||||||
>
|
|
||||||
<MenuItem value={-1}>OFF</MenuItem>
|
|
||||||
<MenuItem value={3}>ERROR</MenuItem>
|
|
||||||
<MenuItem value={4}>WARNING</MenuItem>
|
|
||||||
<MenuItem value={5}>NOTICE</MenuItem>
|
|
||||||
<MenuItem value={6}>INFO</MenuItem>
|
|
||||||
<MenuItem value={7}>DEBUG</MenuItem>
|
|
||||||
<MenuItem value={8}>ALL</MenuItem>
|
|
||||||
</SelectValidator>
|
|
||||||
</Grid>
|
|
||||||
<Grid item md>
|
|
||||||
<Typography color="primary" variant="body2">
|
|
||||||
<i>
|
|
||||||
(the last {data.max_messages} messages are retained and
|
|
||||||
all new log events are shown in real time below)
|
|
||||||
</i>
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</ValidatorForm>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withAuthenticatedContext(LogEventForm);
|
|
||||||
@@ -18,7 +18,7 @@ const ES_ENDPOINT_ROOT = '/es/'
|
|||||||
const LOG_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'logSettings'
|
const LOG_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'logSettings'
|
||||||
const log_settings = {
|
const log_settings = {
|
||||||
level: 6,
|
level: 6,
|
||||||
max_messages: 30,
|
max_messages: 50,
|
||||||
}
|
}
|
||||||
|
|
||||||
const FETCH_LOG_ENDPOINT = REST_ENDPOINT_ROOT + 'fetchLog'
|
const FETCH_LOG_ENDPOINT = REST_ENDPOINT_ROOT + 'fetchLog'
|
||||||
@@ -770,14 +770,22 @@ app.get(FETCH_LOG_ENDPOINT, (req, res) => {
|
|||||||
res.end(null, 'binary')
|
res.end(null, 'binary')
|
||||||
})
|
})
|
||||||
app.get(LOG_SETTINGS_ENDPOINT, (req, res) => {
|
app.get(LOG_SETTINGS_ENDPOINT, (req, res) => {
|
||||||
|
console.log(
|
||||||
|
'Fetching log settings ' +
|
||||||
|
log_settings.level +
|
||||||
|
',' +
|
||||||
|
log_settings.max_messages,
|
||||||
|
)
|
||||||
res.json(log_settings)
|
res.json(log_settings)
|
||||||
})
|
})
|
||||||
app.post(LOG_SETTINGS_ENDPOINT, (req, res) => {
|
app.post(LOG_SETTINGS_ENDPOINT, (req, res) => {
|
||||||
console.log('New log level is ' + req.body.level)
|
console.log(
|
||||||
const data = {
|
'Setting new level=' +
|
||||||
level: req.body.level,
|
req.body.level +
|
||||||
}
|
' max_messages=' +
|
||||||
res.json(data)
|
req.body.max_messages,
|
||||||
|
)
|
||||||
|
res.sendStatus(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
// NETWORK
|
// NETWORK
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.2.0b0"
|
#define EMSESP_APP_VERSION "3.2.0b1"
|
||||||
|
|||||||
@@ -23,21 +23,21 @@ using namespace std::placeholders;
|
|||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
WebLogService::WebLogService(AsyncWebServer * server, SecurityManager * securityManager)
|
WebLogService::WebLogService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||||
: _events(EVENT_SOURCE_LOG_PATH)
|
: events_(EVENT_SOURCE_LOG_PATH)
|
||||||
, _setLevel(LOG_SETTINGS_PATH, std::bind(&WebLogService::setLevel, this, _1, _2), 256) { // for POSTS
|
, setValues_(LOG_SETTINGS_PATH, std::bind(&WebLogService::setValues, this, _1, _2), 256) { // for POSTS
|
||||||
|
|
||||||
_events.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
|
events_.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
|
||||||
server->addHandler(&_events);
|
server->addHandler(&events_);
|
||||||
server->on(EVENT_SOURCE_LOG_PATH, HTTP_GET, std::bind(&WebLogService::forbidden, this, _1));
|
server->on(EVENT_SOURCE_LOG_PATH, HTTP_GET, std::bind(&WebLogService::forbidden, this, _1));
|
||||||
|
|
||||||
// for bring back the whole log
|
// for bring back the whole log
|
||||||
server->on(FETCH_LOG_PATH, HTTP_GET, std::bind(&WebLogService::fetchLog, this, _1));
|
server->on(FETCH_LOG_PATH, HTTP_GET, std::bind(&WebLogService::fetchLog, this, _1));
|
||||||
|
|
||||||
// get when page is loaded
|
// get when page is loaded
|
||||||
server->on(LOG_SETTINGS_PATH, HTTP_GET, std::bind(&WebLogService::getLevel, this, _1));
|
server->on(LOG_SETTINGS_PATH, HTTP_GET, std::bind(&WebLogService::getValues, this, _1));
|
||||||
|
|
||||||
// for setting a level
|
// for setting a level
|
||||||
server->addHandler(&_setLevel);
|
server->addHandler(&setValues_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebLogService::forbidden(AsyncWebServerRequest * request) {
|
void WebLogService::forbidden(AsyncWebServerRequest * request) {
|
||||||
@@ -90,7 +90,7 @@ void WebLogService::operator<<(std::shared_ptr<uuid::log::Message> message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebLogService::loop() {
|
void WebLogService::loop() {
|
||||||
if (!_events.count() || log_messages_.empty()) {
|
if (!events_.count() || log_messages_.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,12 +144,12 @@ void WebLogService::transmit(const QueuedLogMessage & message) {
|
|||||||
char * buffer = new char[len + 1];
|
char * buffer = new char[len + 1];
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
serializeJson(jsonDocument, buffer, len + 1);
|
serializeJson(jsonDocument, buffer, len + 1);
|
||||||
_events.send(buffer, "message", millis());
|
events_.send(buffer, "message", millis());
|
||||||
}
|
}
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the current log buffer to the API
|
// send the complete log buffer to the API, filtering on log level
|
||||||
void WebLogService::fetchLog(AsyncWebServerRequest * request) {
|
void WebLogService::fetchLog(AsyncWebServerRequest * request) {
|
||||||
MsgpackAsyncJsonResponse * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE_DYN); // 8kb buffer
|
MsgpackAsyncJsonResponse * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE_DYN); // 8kb buffer
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
@@ -157,15 +157,17 @@ void WebLogService::fetchLog(AsyncWebServerRequest * request) {
|
|||||||
JsonArray log = root.createNestedArray("events");
|
JsonArray log = root.createNestedArray("events");
|
||||||
|
|
||||||
for (const auto & msg : log_messages_) {
|
for (const auto & msg : log_messages_) {
|
||||||
JsonObject logEvent = log.createNestedObject();
|
if (msg.content_->level <= log_level()) {
|
||||||
auto message = std::move(msg);
|
JsonObject logEvent = log.createNestedObject();
|
||||||
char time_string[25];
|
auto message = std::move(msg);
|
||||||
|
char time_string[25];
|
||||||
|
|
||||||
logEvent["t"] = messagetime(time_string, message.content_->uptime_ms);
|
logEvent["t"] = messagetime(time_string, message.content_->uptime_ms);
|
||||||
logEvent["l"] = message.content_->level;
|
logEvent["l"] = message.content_->level;
|
||||||
logEvent["i"] = message.id_;
|
logEvent["i"] = message.id_;
|
||||||
logEvent["n"] = message.content_->name;
|
logEvent["n"] = message.content_->name;
|
||||||
logEvent["m"] = message.content_->text;
|
logEvent["m"] = message.content_->text;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log_message_id_tail_ = log_messages_.back().id_;
|
log_message_id_tail_ = log_messages_.back().id_;
|
||||||
@@ -174,28 +176,25 @@ void WebLogService::fetchLog(AsyncWebServerRequest * request) {
|
|||||||
request->send(response);
|
request->send(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets the level after a POST
|
// sets the values like level after a POST
|
||||||
void WebLogService::setLevel(AsyncWebServerRequest * request, JsonVariant & json) {
|
void WebLogService::setValues(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||||
if (not json.is<JsonObject>()) {
|
if (not json.is<JsonObject>()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto && body = json.as<JsonObject>();
|
|
||||||
|
auto && body = json.as<JsonObject>();
|
||||||
|
|
||||||
uuid::log::Level level = body["level"];
|
uuid::log::Level level = body["level"];
|
||||||
log_level(level);
|
log_level(level);
|
||||||
if (level == uuid::log::Level::OFF) {
|
|
||||||
log_messages_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// send the value back
|
uint8_t max_messages = body["max_messages"];
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
|
maximum_log_messages(max_messages);
|
||||||
JsonObject root = response->getRoot();
|
|
||||||
root["level"] = log_level();
|
request->send(200); // OK
|
||||||
response->setLength();
|
|
||||||
request->send(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the current log level after a GET
|
// return the current value settings after a GET
|
||||||
void WebLogService::getLevel(AsyncWebServerRequest * request) {
|
void WebLogService::getValues(AsyncWebServerRequest * request) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
|
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
root["level"] = log_level();
|
root["level"] = log_level();
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace emsesp {
|
|||||||
|
|
||||||
class WebLogService : public uuid::log::Handler {
|
class WebLogService : public uuid::log::Handler {
|
||||||
public:
|
public:
|
||||||
static constexpr size_t MAX_LOG_MESSAGES = 30;
|
static constexpr size_t MAX_LOG_MESSAGES = 50;
|
||||||
static constexpr size_t REFRESH_SYNC = 200;
|
static constexpr size_t REFRESH_SYNC = 200;
|
||||||
|
|
||||||
WebLogService(AsyncWebServer * server, SecurityManager * securityManager);
|
WebLogService(AsyncWebServer * server, SecurityManager * securityManager);
|
||||||
@@ -49,7 +49,7 @@ class WebLogService : public uuid::log::Handler {
|
|||||||
virtual void operator<<(std::shared_ptr<uuid::log::Message> message);
|
virtual void operator<<(std::shared_ptr<uuid::log::Message> message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AsyncEventSource _events;
|
AsyncEventSource events_;
|
||||||
|
|
||||||
class QueuedLogMessage {
|
class QueuedLogMessage {
|
||||||
public:
|
public:
|
||||||
@@ -64,12 +64,12 @@ class WebLogService : public uuid::log::Handler {
|
|||||||
void forbidden(AsyncWebServerRequest * request);
|
void forbidden(AsyncWebServerRequest * request);
|
||||||
void transmit(const QueuedLogMessage & message);
|
void transmit(const QueuedLogMessage & message);
|
||||||
void fetchLog(AsyncWebServerRequest * request);
|
void fetchLog(AsyncWebServerRequest * request);
|
||||||
void getLevel(AsyncWebServerRequest * request);
|
void getValues(AsyncWebServerRequest * request);
|
||||||
|
|
||||||
char * messagetime(char * out, const uint64_t t);
|
char * messagetime(char * out, const uint64_t t);
|
||||||
|
|
||||||
void setLevel(AsyncWebServerRequest * request, JsonVariant & json);
|
void setValues(AsyncWebServerRequest * request, JsonVariant & json);
|
||||||
AsyncCallbackJsonWebHandler _setLevel; // for POSTs
|
AsyncCallbackJsonWebHandler setValues_; // for POSTs
|
||||||
|
|
||||||
uint64_t last_transmit_ = 0; // Last transmit time
|
uint64_t last_transmit_ = 0; // Last transmit time
|
||||||
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; // Maximum number of log messages to buffer before they are output
|
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; // Maximum number of log messages to buffer before they are output
|
||||||
|
|||||||
Reference in New Issue
Block a user