WIP - logger migrations; initial work for data bag view widget

This commit is contained in:
2023-01-17 10:43:11 -06:00
parent 178078282c
commit 46adfa8e24
8 changed files with 448 additions and 127 deletions

View File

@ -0,0 +1,92 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.actions.dashboard.widgets;
import java.util.Map;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.QWidgetData;
/*******************************************************************************
**
*******************************************************************************/
public class DefaultWidgetRenderer extends AbstractWidgetRenderer
{
/*******************************************************************************
**
*******************************************************************************/
@Override
public RenderWidgetOutput render(RenderWidgetInput input) throws QException
{
return new RenderWidgetOutput(new DefaultWidgetData(input));
}
/*******************************************************************************
**
*******************************************************************************/
public static class DefaultWidgetData extends QWidgetData
{
private final String type;
private final Map<String, String> queryParams;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public DefaultWidgetData(RenderWidgetInput renderWidgetInput)
{
this.type = renderWidgetInput.getWidgetMetaData().getType();
this.queryParams = renderWidgetInput.getQueryParams();
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public String getType()
{
return (type);
}
/*******************************************************************************
** Getter for queryParams
**
*******************************************************************************/
public Map<String, String> getQueryParams()
{
return queryParams;
}
}
}

View File

@ -0,0 +1,106 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.logging;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
/*******************************************************************************
**
*******************************************************************************/
public class LogPair
{
private String key;
private Object value;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public LogPair(String key, Object value)
{
this.key = key;
this.value = value;
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public String toString()
{
String valueString = getValueString(value);
return "\"" + Objects.requireNonNullElse(key, "null").replace('"', '.') + "\":" + valueString;
}
/*******************************************************************************
**
*******************************************************************************/
private String getValueString(Object value)
{
String valueString;
if(value == null)
{
valueString = "null";
}
else if(value instanceof LogPair subLogPair)
{
valueString = '{' + subLogPair.toString() + '}';
}
else if(value instanceof LogPair[] subLogPairs)
{
String subLogPairsString = Arrays.stream(subLogPairs).map(LogPair::toString).collect(Collectors.joining(","));
valueString = '{' + subLogPairsString + '}';
}
else if(value instanceof LogUtils.UnsafeSupplier us)
{
try
{
Object o = us.get();
return getValueString(o);
}
catch(Exception e)
{
valueString = "LogValueError";
}
}
else if(value instanceof Number n)
{
valueString = String.valueOf(n);
}
else
{
valueString = '"' + String.valueOf(value).replace("\"", "\\\"") + '"';
}
return valueString;
}
}

View File

@ -1,6 +1,6 @@
/* /*
* QQQ - Low-code Application Framework for Engineers. * QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC * Copyright (C) 2021-2023. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com * contact@kingsrook.com
* https://github.com/Kingsrook/ * https://github.com/Kingsrook/
@ -19,7 +19,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.kingsrook.qqq.backend.core.utils; package com.kingsrook.qqq.backend.core.logging;
import java.util.Arrays; import java.util.Arrays;
@ -34,6 +34,22 @@ import java.util.stream.Collectors;
public class LogUtils public class LogUtils
{ {
/*******************************************************************************
**
*******************************************************************************/
public static String jsonLog(List<LogPair> logPairs)
{
List<LogPair> filteredList = logPairs.stream().filter(Objects::nonNull).toList();
if(filteredList.isEmpty())
{
return ("{}");
}
return ('{' + filteredList.stream().map(LogPair::toString).collect(Collectors.joining(",")) + '}');
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@ -44,13 +60,7 @@ public class LogUtils
return ("{}"); return ("{}");
} }
List<LogPair> filteredList = Arrays.stream(logPairs).filter(Objects::nonNull).toList(); return (jsonLog(Arrays.asList(logPairs)));
if(filteredList.isEmpty())
{
return ("{}");
}
return ('{' + filteredList.stream().map(LogPair::toString).collect(Collectors.joining(",")) + '}');
} }
@ -75,86 +85,6 @@ public class LogUtils
/*******************************************************************************
**
*******************************************************************************/
public static class LogPair
{
private String key;
private Object value;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public LogPair(String key, Object value)
{
this.key = key;
this.value = value;
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public String toString()
{
String valueString = getValueString(value);
return "\"" + Objects.requireNonNullElse(key, "null").replace('"', '.') + "\":" + valueString;
}
/*******************************************************************************
**
*******************************************************************************/
private String getValueString(Object value)
{
String valueString;
if(value == null)
{
valueString = "null";
}
else if(value instanceof LogPair subLogPair)
{
valueString = '{' + subLogPair.toString() + '}';
}
else if(value instanceof LogPair[] subLogPairs)
{
String subLogPairsString = Arrays.stream(subLogPairs).map(LogPair::toString).collect(Collectors.joining(","));
valueString = '{' + subLogPairsString + '}';
}
else if(value instanceof UnsafeSupplier us)
{
try
{
Object o = us.get();
return getValueString(o);
}
catch(Exception e)
{
valueString = "LogValueError";
}
}
else if(value instanceof Number n)
{
valueString = String.valueOf(n);
}
else
{
valueString = '"' + String.valueOf(value).replace("\"", "\\\"") + '"';
}
return valueString;
}
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/

View File

@ -47,7 +47,8 @@ public enum WidgetType
SIMPLE_STATISTICS("simpleStatistics"), SIMPLE_STATISTICS("simpleStatistics"),
STEPPER("stepper"), STEPPER("stepper"),
TABLE("table"), TABLE("table"),
USA_MAP("usaMap"); USA_MAP("usaMap"),
DATA_BAG_VIEWER("dataBagViewer");
private final String type; private final String type;

View File

@ -22,13 +22,20 @@
package com.kingsrook.qqq.backend.core.utils; package com.kingsrook.qqq.backend.core.utils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.logging.LogPair;
import com.kingsrook.qqq.backend.core.logging.LogUtils;
import com.kingsrook.qqq.backend.core.model.session.QSession; import com.kingsrook.qqq.backend.core.model.session.QSession;
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/******************************************************************************* /*******************************************************************************
@ -37,10 +44,20 @@ import org.apache.logging.log4j.Logger;
*******************************************************************************/ *******************************************************************************/
public class QLogger public class QLogger
{ {
private static Map<String, QLogger> loggerMap = new HashMap<>(); private static Map<String, QLogger> loggerMap = Collections.synchronizedMap(new HashMap<>());
private static boolean logSessionIdEnabled = true;
private Logger logger; private Logger logger;
static
{
String propertyName = "qqq.logger.logSessionId.disabled";
String propertyValue = System.getProperty(propertyName, "");
if(propertyValue.equals("true"))
{
logSessionIdEnabled = false;
}
}
/******************************************************************************* /*******************************************************************************
** **
@ -67,7 +84,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void log(Level level, String message) public void log(Level level, String message)
{ {
logger.log(level, wrapMessage(message)); logger.log(level, messageToJsonString(message));
} }
@ -77,7 +94,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void log(Level level, String message, Throwable t) public void log(Level level, String message, Throwable t)
{ {
logger.log(level, wrapMessage(message), t); logger.log(level, messageToJsonString(message), t);
} }
@ -97,7 +114,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void trace(String message) public void trace(String message)
{ {
logger.trace(wrapMessage(message)); logger.trace(messageToJsonString(message));
} }
@ -107,7 +124,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void trace(String message, Object... values) public void trace(String message, Object... values)
{ {
logger.trace(wrapMessage(message), values); logger.trace(messageToJsonString(message), values);
} }
@ -117,7 +134,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void trace(String message, Throwable t) public void trace(String message, Throwable t)
{ {
logger.trace(wrapMessage(message), t); logger.trace(messageToJsonString(message), t);
} }
@ -137,7 +154,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void debug(String message) public void debug(String message)
{ {
logger.debug(wrapMessage(message)); logger.debug(messageToJsonString(message));
} }
@ -147,7 +164,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void debug(String message, Object... values) public void debug(String message, Object... values)
{ {
logger.debug(wrapMessage(message), values); logger.debug(messageToJsonString(message), values);
} }
@ -157,7 +174,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void debug(String message, Throwable t) public void debug(String message, Throwable t)
{ {
logger.debug(wrapMessage(message), t); logger.debug(messageToJsonString(message), t);
} }
@ -177,7 +194,27 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void info(String message) public void info(String message)
{ {
logger.info(wrapMessage(message)); logger.info(messageToJsonString(message));
}
/*******************************************************************************
**
*******************************************************************************/
public void info(LogPair... logPairs)
{
logger.info(LogUtils.jsonLog(addSessionLogPair(Arrays.asList(logPairs))));
}
/*******************************************************************************
**
*******************************************************************************/
public void info(List<LogPair> logPairList)
{
logger.info(LogUtils.jsonLog(addSessionLogPair(logPairList)));
} }
@ -187,7 +224,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void info(String message, Object... values) public void info(String message, Object... values)
{ {
logger.info(wrapMessage(message), values); logger.info(messageToJsonString(message), values);
} }
@ -197,7 +234,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void info(String message, Throwable t) public void info(String message, Throwable t)
{ {
logger.info(wrapMessage(message), t); logger.info(messageToJsonString(message), t);
} }
@ -217,7 +254,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void warn(String message) public void warn(String message)
{ {
logger.warn(wrapMessage(message)); logger.warn(messageToJsonString(message));
} }
@ -227,7 +264,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void warn(String message, Object... values) public void warn(String message, Object... values)
{ {
logger.warn(wrapMessage(message), values); logger.warn(messageToJsonString(message), values);
} }
@ -237,7 +274,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void warn(String message, Throwable t) public void warn(String message, Throwable t)
{ {
logger.warn(wrapMessage(message), t); logger.warn(messageToJsonString(message), t);
} }
@ -257,7 +294,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void error(String message) public void error(String message)
{ {
logger.error(wrapMessage(message)); logger.error(messageToJsonString(message));
} }
@ -267,7 +304,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void error(String message, Object... values) public void error(String message, Object... values)
{ {
logger.error(wrapMessage(message), values); logger.error(messageToJsonString(message), values);
} }
@ -277,7 +314,7 @@ public class QLogger
*******************************************************************************/ *******************************************************************************/
public void error(String message, Throwable t) public void error(String message, Throwable t)
{ {
logger.error(wrapMessage(message), t); logger.error(messageToJsonString(message), t);
} }
@ -295,17 +332,54 @@ public class QLogger
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
private String wrapMessage(String message) private String messageToJsonString(String message)
{ {
String propertyName = "qqq.logger.logSessionId.disabled"; List<LogPair> logPairList = new ArrayList<>();
String propertyValue = System.getProperty(propertyName, ""); logPairList.add(logPair("message", message));
if(propertyValue.equals("true")) addSessionLogPair(logPairList);
{
return (message); return (LogUtils.jsonLog(logPairList));
} }
/*******************************************************************************
**
*******************************************************************************/
private static List<LogPair> addSessionLogPair(List<LogPair> logPairList)
{
if(logSessionIdEnabled)
{
QSession session = QContext.getQSession(); QSession session = QContext.getQSession();
String sessionString = (session != null) ? session.getUuid() : "Not provided"; LogPair sessionLogPair;
return ("Session [" + sessionString + "] | " + message);
if(session == null)
{
sessionLogPair = logPair("session", "unknown");
}
else
{
String user = "unknown";
if(session.getUser() != null)
{
user = session.getUser().getIdReference();
}
sessionLogPair = logPair("session", logPair("id", session.getUuid()), logPair("user", user));
}
try
{
logPairList.add(sessionLogPair);
}
catch(Exception e)
{
//////////////////////////////////////
// deal with not-modifiable list... //
//////////////////////////////////////
logPairList = new ArrayList<>(logPairList);
logPairList.add(sessionLogPair);
}
}
return (logPairList);
} }
} }

View File

@ -24,14 +24,15 @@ package com.kingsrook.qqq.backend.core.utils;
import java.math.BigDecimal; import java.math.BigDecimal;
import com.kingsrook.qqq.backend.core.BaseTest; import com.kingsrook.qqq.backend.core.BaseTest;
import com.kingsrook.qqq.backend.core.logging.LogPair;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static com.kingsrook.qqq.backend.core.utils.LogUtils.jsonLog; import static com.kingsrook.qqq.backend.core.logging.LogUtils.jsonLog;
import static com.kingsrook.qqq.backend.core.utils.LogUtils.logPair; import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
/******************************************************************************* /*******************************************************************************
** Unit test for com.kingsrook.qqq.backend.core.utils.LogUtils ** Unit test for com.kingsrook.qqq.backend.core.logging.LogUtils
*******************************************************************************/ *******************************************************************************/
class LogUtilsTest extends BaseTest class LogUtilsTest extends BaseTest
{ {
@ -49,12 +50,12 @@ class LogUtilsTest extends BaseTest
// null cases // // null cases //
//////////////// ////////////////
assertEquals("{}", jsonLog()); assertEquals("{}", jsonLog());
assertEquals("{}", jsonLog((LogUtils.LogPair) null)); assertEquals("{}", jsonLog((LogPair) null));
assertEquals("{}", jsonLog((LogUtils.LogPair[]) null)); assertEquals("{}", jsonLog((LogPair[]) null));
assertEquals(""" assertEquals("""
{"null":null}""", jsonLog(logPair(null, (LogUtils.LogPair) null))); {"null":null}""", jsonLog(logPair(null, (LogPair) null)));
assertEquals(""" assertEquals("""
{"null":null}""", jsonLog(logPair(null, (LogUtils.LogPair[]) null))); {"null":null}""", jsonLog(logPair(null, (LogPair[]) null)));
////////////// //////////////
// escaping // // escaping //

View File

@ -0,0 +1,109 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.javalin;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.kingsrook.qqq.backend.core.logging.LogPair;
import com.kingsrook.qqq.backend.core.utils.QLogger;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/*******************************************************************************
**
*******************************************************************************/
public class QJavalinAccessLogger
{
private static final QLogger LOG = QLogger.getLogger(QJavalinAccessLogger.class);
private static ThreadLocal<Long> requestStartTime = new ThreadLocal<>();
private static ThreadLocal<String> requestActionName = new ThreadLocal<>();
/*******************************************************************************
**
*******************************************************************************/
static void logStart(String actionName, LogPair... logPairs)
{
requestStartTime.set(System.currentTimeMillis());
requestActionName.set(actionName);
List<LogPair> pairList = new ArrayList<>(Arrays.asList(logPairs));
pairList.add(0, logPair("access", "start"));
pairList.add(1, logPair("action", actionName));
LOG.info(pairList);
}
/*******************************************************************************
**
*******************************************************************************/
static void logEndSuccess(LogPair... logPairs)
{
List<LogPair> pairList = new ArrayList<>(Arrays.asList(logPairs));
pairList.add(0, logPair("access", "end-ok"));
accessLogEnd(pairList);
}
/*******************************************************************************
**
*******************************************************************************/
static void logEndFail(Throwable t, LogPair... logPairs)
{
List<LogPair> pairList = new ArrayList<>(Arrays.asList(logPairs));
pairList.add(0, logPair("access", "end-fail"));
pairList.add(1, logPair("exceptionType", t.getClass().getSimpleName()));
pairList.add(2, logPair("exceptionMessage", t.getMessage()));
accessLogEnd(pairList);
}
/*******************************************************************************
**
*******************************************************************************/
private static void accessLogEnd(List<LogPair> pairList)
{
String actionName = requestActionName.get();
requestActionName.remove();
if(StringUtils.hasContent(actionName))
{
pairList.add(1, logPair("action", actionName));
}
Long startTime = requestStartTime.get();
requestStartTime.remove();
if(startTime != null)
{
long endTime = System.currentTimeMillis();
pairList.add(logPair("millis", (endTime - startTime)));
}
LOG.info(pairList);
}
}

View File

@ -107,6 +107,7 @@ import io.javalin.apibuilder.EndpointGroup;
import io.javalin.http.Context; import io.javalin.http.Context;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
import static io.javalin.apibuilder.ApiBuilder.delete; import static io.javalin.apibuilder.ApiBuilder.delete;
import static io.javalin.apibuilder.ApiBuilder.get; import static io.javalin.apibuilder.ApiBuilder.get;
import static io.javalin.apibuilder.ApiBuilder.patch; import static io.javalin.apibuilder.ApiBuilder.patch;
@ -708,11 +709,15 @@ public class QJavalinImplementation
*******************************************************************************/ *******************************************************************************/
static void dataQuery(Context context) static void dataQuery(Context context)
{ {
String table = context.pathParam("table");
try try
{ {
QueryInput queryInput = new QueryInput(); QueryInput queryInput = new QueryInput();
setupSession(context, queryInput); setupSession(context, queryInput);
queryInput.setTableName(context.pathParam("table")); QJavalinAccessLogger.logStart("query", logPair("table", table));
queryInput.setTableName(table);
queryInput.setShouldGenerateDisplayValues(true); queryInput.setShouldGenerateDisplayValues(true);
queryInput.setShouldTranslatePossibleValues(true); queryInput.setShouldTranslatePossibleValues(true);
queryInput.setSkip(integerQueryParam(context, "skip")); queryInput.setSkip(integerQueryParam(context, "skip"));
@ -733,10 +738,13 @@ public class QJavalinImplementation
QueryAction queryAction = new QueryAction(); QueryAction queryAction = new QueryAction();
QueryOutput queryOutput = queryAction.execute(queryInput); QueryOutput queryOutput = queryAction.execute(queryInput);
QJavalinAccessLogger.logEndSuccess(logPair("table", table), logPair("recordCount", queryOutput.getRecords().size()));
context.result(JsonUtils.toJson(queryOutput)); context.result(JsonUtils.toJson(queryOutput));
} }
catch(Exception e) catch(Exception e)
{ {
QJavalinAccessLogger.logEndFail(e, logPair("table", table));
handleException(context, e); handleException(context, e);
} }
} }