Skip to content

Commit

Permalink
Dev UI - add logger level to server log
Browse files Browse the repository at this point in the history
Signed-off-by: Phillip Kruger <[email protected]>
  • Loading branch information
phillip-kruger committed Apr 19, 2023
1 parent 0036931 commit b63fd25
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
package io.quarkus.devui.deployment;

import static java.util.logging.Level.ALL;
import static java.util.logging.Level.CONFIG;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.FINER;
import static java.util.logging.Level.FINEST;
import static java.util.logging.Level.OFF;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Level.WARNING;
import static org.jboss.logmanager.Level.DEBUG;
import static org.jboss.logmanager.Level.ERROR;
import static org.jboss.logmanager.Level.FATAL;
import static org.jboss.logmanager.Level.INFO;
import static org.jboss.logmanager.Level.TRACE;
import static org.jboss.logmanager.Level.WARN;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
Expand Down Expand Up @@ -379,6 +394,7 @@ private void addFooterTabBuildTimeData(BuildTimeConstBuildItem internalBuildTime
}

internalBuildTimeData.addBuildTimeData("footerTabs", footerTabs);
internalBuildTimeData.addBuildTimeData("loggerLevels", LEVELS);
}

private void addVersionInfoBuildTimeData(BuildTimeConstBuildItem internalBuildTimeData,
Expand All @@ -394,6 +410,22 @@ private void addVersionInfoBuildTimeData(BuildTimeConstBuildItem internalBuildTi
internalBuildTimeData.addBuildTimeData("applicationInfo", applicationInfo);
}

private static final List<String> LEVELS = List.of(
OFF.getName(),
SEVERE.getName(),
ERROR.getName(),
FATAL.getName(),
WARNING.getName(),
WARN.getName(),
INFO.getName(),
DEBUG.getName(),
TRACE.getName(),
CONFIG.getName(),
FINE.getName(),
FINER.getName(),
FINEST.getName(),
ALL.getName());

private static void computeColors(Map<String, Map<String, String>> themes, Map<String, String> dark,
Map<String, String> light) {
// Quarkus logo colors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ import { JsonRpc } from 'jsonrpc';
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
import '@vaadin/icon';
import '@vaadin/dialog';
import '@vaadin/select';
import '@vaadin/checkbox';
import '@vaadin/checkbox-group';
import { dialogHeaderRenderer, dialogRenderer } from '@vaadin/dialog/lit.js';
import 'qui-badge';
import '@vaadin/grid';
import { columnBodyRenderer } from '@vaadin/grid/lit.js';
import '@vaadin/grid/vaadin-grid-sort-column.js';
import '@vaadin/vertical-layout';
import { loggerLevels } from 'devui-data';

/**
* This component represent the Server Log
Expand Down Expand Up @@ -73,13 +79,6 @@ export class QwcServerLog extends QwcHotReloadElement {
color: var(--lumo-success-color-50pct);
}
.columnsDialog{
}
.levelsDialog{
}
`;

static properties = {
Expand All @@ -91,10 +90,22 @@ export class QwcServerLog extends QwcHotReloadElement {
_levelsDialogOpened: {state: true},
_columnsDialogOpened: {state: true},
_selectedColumns: {state: true},
_allLoggers: {state: true, type: Array},
_filteredLoggers: {state: true, type: Array},
_loggerLevels: {state: false, type: Array}
};

constructor() {
super();
this._loggerLevels = [];
for (let i in loggerLevels) {
let loggerLevel = loggerLevels[i];
this._loggerLevels.push({
'label': loggerLevel,
'value': loggerLevel,
});
}

this.logControl
.addToggle("On/off switch", true, (e) => {
this._toggleOnOffClicked(e);
Expand Down Expand Up @@ -129,18 +140,28 @@ export class QwcServerLog extends QwcHotReloadElement {
this._addLogEntry(entry);
});
});
this._loadAllLoggers();
}

disconnectedCallback() {
super.disconnectedCallback();
this._toggleOnOff(false);
}

_loadAllLoggers(){
this.jsonRpc.getLoggers().then(jsonRpcResponse => {
this._allLoggers = jsonRpcResponse.result;
this._filteredLoggers = this._allLoggers;
});
}

render() {

return html`
if(this._filteredLoggers){
return html`
<vaadin-dialog class="levelsDialog"
header-title="Log levels"
header-title="Log levels (${this._filteredLoggers.length})"
resizable
draggable
.opened="${this._levelsDialogOpened}"
@opened-changed="${(e) => (this._levelsDialogOpened = e.detail.value)}"
${dialogHeaderRenderer(() => html`
Expand All @@ -154,6 +175,8 @@ export class QwcServerLog extends QwcHotReloadElement {
></vaadin-dialog>
<vaadin-dialog class="columnsDialog"
header-title="Columns"
resizable
draggable
.opened="${this._columnsDialogOpened}"
@opened-changed="${(e) => (this._columnsDialogOpened = e.detail.value)}"
${dialogHeaderRenderer(() => html`
Expand All @@ -176,7 +199,7 @@ export class QwcServerLog extends QwcHotReloadElement {
`
)}
</code>`;

}
}

_renderLogEntry(message){
Expand Down Expand Up @@ -379,11 +402,80 @@ export class QwcServerLog extends QwcHotReloadElement {
}

_renderLevelsDialog(){
return html`
Hello levels
`;
if(this._filteredLoggers){
return html`<vaadin-vertical-layout
theme="spacing"
style="width: 600px; max-width: 100%; min-width: 300px; height: 100%; align-items: stretch;">
<vaadin-text-field
placeholder="Filter"
style="width: 100%;"
@value-changed="${(e) => this._filterLoggers(e)}">
<vaadin-icon slot="prefix" icon="font-awesome-solid:filter"></vaadin-icon>
</vaadin-text-field>
<vaadin-grid .items="${this._filteredLoggers}" style="width: 100%;" theme="row-stripes">
<vaadin-grid-sort-column resizable
header="Name"
path="name">
</vaadin-grid-sort-column>
<vaadin-grid-column auto-width resizable flex-grow="0"
class="cell"
header="Level"
${columnBodyRenderer(this._logLevelRenderer, [])}>
</vaadin-grid>
</vaadin-vertical-layout>
`;
}
}

_filterLoggers(e) {
const searchTerm = (e.detail.value || '').trim();
if (searchTerm === '') {
this._filteredLoggers = this._allLoggers;
return;
}

this._filteredLoggers = this._allLoggers.filter((level) => {
let i = this._matchLogger(level.name, searchTerm);
return i;
});
}

_matchLogger(value, term) {
if (!value) {
return false;
}
return value.toLowerCase().includes(term.toLowerCase());
}

_logLevelRenderer(logger){
return html`${this._renderSelect(logger.name, logger.effectiveLevel)}`;
}

_renderSelect(loggerName, loggerLevel){
return html`<vaadin-select class="input-column"
id="${loggerName}"
theme="small"
.items="${this._loggerLevels}"
.value="${loggerLevel}"
@change="${this._logLevelSelectChanged}">
</vaadin-select>`;
}

_logLevelSelectChanged(event){
let name = event.target.id;
this._updateLogLevel(name, event.target.value);
}

_updateLogLevel(name, value){
this.jsonRpc.updateLogLevel({
'loggerName': name,
'levelValue': value
});
}

_renderColumnsDialog(){
return html`<vaadin-checkbox-group
.value="${this._selectedColumns}"
Expand Down Expand Up @@ -446,6 +538,7 @@ export class QwcServerLog extends QwcHotReloadElement {
hotReload(){
this._toggleOnOffClicked(false);
this._toggleOnOffClicked(true);
this._loadAllLoggers();
}

_toggleFollowLog(e){
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package io.quarkus.devui.runtime.logstream;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;

import org.jboss.logmanager.LogContext;
import org.jboss.logmanager.Logger;

import io.quarkus.arc.Arc;
import io.smallrye.common.annotation.NonBlocking;
Expand All @@ -13,6 +18,7 @@
* This makes the log file available via json RPC
*/
public class LogStreamJsonRPCService {
private static final org.jboss.logging.Logger LOG = org.jboss.logging.Logger.getLogger(LogStreamJsonRPCService.class);

@NonBlocking
public String ping() {
Expand All @@ -31,4 +37,66 @@ public Multi<JsonObject> streamLog() {
return logStreamBroadcaster.getLogStream();
}

@NonBlocking
public List<JsonObject> getLoggers() {
LogContext logContext = LogContext.getLogContext();
List<JsonObject> values = new ArrayList<>();
Enumeration<String> loggerNames = logContext.getLoggerNames();
while (loggerNames.hasMoreElements()) {
String loggerName = loggerNames.nextElement();
JsonObject jsonObject = getLogger(loggerName);
if (jsonObject != null) {
values.add(jsonObject);
}
}
return values;
}

@NonBlocking
public JsonObject getLogger(String loggerName) {
LogContext logContext = LogContext.getLogContext();
if (loggerName != null && !loggerName.isEmpty()) {
Logger logger = logContext.getLogger(loggerName);
return JsonObject.of(
"name", loggerName,
"effectiveLevel", getEffectiveLogLevel(logger),
"configuredLevel", getConfiguredLogLevel(logger));
}
return null;
}

@NonBlocking
public JsonObject updateLogLevel(String loggerName, String levelValue) {
LogContext logContext = LogContext.getLogContext();
Logger logger = logContext.getLogger(loggerName);
java.util.logging.Level level;
if (levelValue == null || levelValue.isBlank()) {
if (logger.getParent() != null) {
level = logger.getParent().getLevel();
} else {
throw new IllegalArgumentException("The level of the root logger cannot be set to null");
}
} else {
level = Level.parse(levelValue);
}
logger.setLevel(level);
LOG.info("Log level updated [" + loggerName + "] changed to [" + levelValue + "]");

return getLogger(loggerName);
}

private String getConfiguredLogLevel(Logger logger) {
java.util.logging.Level level = logger.getLevel();
return level != null ? level.getName() : null;
}

private String getEffectiveLogLevel(Logger logger) {
if (logger == null) {
return null;
}
if (logger.getLevel() != null) {
return logger.getLevel().getName();
}
return getEffectiveLogLevel(logger.getParent());
}
}

0 comments on commit b63fd25

Please sign in to comment.