-
Notifications
You must be signed in to change notification settings - Fork 441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve log mediator to support string templating #2230
Changes from all commits
1fa4291
6b6baaa
781686c
2463b2c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,12 +32,13 @@ | |
import org.apache.synapse.core.axis2.Axis2MessageContext; | ||
import org.apache.synapse.mediators.AbstractMediator; | ||
import org.apache.synapse.mediators.MediatorProperty; | ||
import org.apache.synapse.util.InlineExpressionUtil; | ||
import org.jaxen.JaxenException; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
|
||
|
||
/** | ||
* Logs the specified message into the configured logger. The log levels specify | ||
* which attributes would be logged, and is configurable. Additionally custom | ||
|
@@ -56,6 +57,9 @@ public class LogMediator extends AbstractMediator { | |
/** all attributes of level 'simple' and the SOAP envelope and any properties */ | ||
public static final int FULL = 3; | ||
|
||
/** The message template and the additional properties specified to the Log mediator */ | ||
public static final int MESSAGE_TEMPLATE = 4; | ||
|
||
public static final int CATEGORY_INFO = 0; | ||
public static final int CATEGORY_DEBUG = 1; | ||
public static final int CATEGORY_TRACE = 2; | ||
|
@@ -74,6 +78,9 @@ public class LogMediator extends AbstractMediator { | |
/** The holder for the custom properties */ | ||
private final List<MediatorProperty> properties = new ArrayList<MediatorProperty>(); | ||
|
||
private String messageTemplate = ""; | ||
private boolean isContentAware = false; | ||
|
||
/** | ||
* Logs the current message according to the supplied semantics | ||
* | ||
|
@@ -136,6 +143,7 @@ public boolean mediate(MessageContext synCtx) { | |
private String getLogMessage(MessageContext synCtx) { | ||
switch (logLevel) { | ||
case CUSTOM: | ||
case MESSAGE_TEMPLATE: | ||
return getCustomLogMessage(synCtx); | ||
case SIMPLE: | ||
return getSimpleLogMessage(synCtx); | ||
|
@@ -150,12 +158,18 @@ private String getLogMessage(MessageContext synCtx) { | |
|
||
private String getCustomLogMessage(MessageContext synCtx) { | ||
StringBuffer sb = new StringBuffer(); | ||
processMessageTemplate(sb, synCtx, messageTemplate); | ||
setCustomProperties(sb, synCtx); | ||
return trimLeadingSeparator(sb); | ||
} | ||
|
||
private String getSimpleLogMessage(MessageContext synCtx) { | ||
StringBuffer sb = new StringBuffer(); | ||
processMessageTemplate(sb, synCtx, messageTemplate); | ||
// append separator if the message template is not empty | ||
if (sb.length() > 0) { | ||
sb.append(separator); | ||
} | ||
if (synCtx.getTo() != null) | ||
sb.append("To: ").append(synCtx.getTo().getAddress()); | ||
else | ||
|
@@ -180,6 +194,7 @@ private String getSimpleLogMessage(MessageContext synCtx) { | |
|
||
private String getHeadersLogMessage(MessageContext synCtx) { | ||
StringBuffer sb = new StringBuffer(); | ||
processMessageTemplate(sb, synCtx, messageTemplate); | ||
if (synCtx.getEnvelope() != null) { | ||
SOAPHeader header = synCtx.getEnvelope().getHeader(); | ||
if (getCorrelationId(synCtx) != null) | ||
|
@@ -288,6 +303,16 @@ public void setCategory(int category) { | |
} | ||
} | ||
|
||
public String getMessageTemplate() { | ||
|
||
return messageTemplate; | ||
} | ||
|
||
public void setMessageTemplate(String messageTemplate) { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same as above |
||
this.messageTemplate = messageTemplate.replace("\\n", "\n").replace("\\t", "\t"); | ||
} | ||
|
||
private String trimLeadingSeparator(StringBuffer sb) { | ||
String retStr = sb.toString(); | ||
if (retStr.startsWith(separator)) { | ||
|
@@ -297,16 +322,32 @@ private String trimLeadingSeparator(StringBuffer sb) { | |
} | ||
} | ||
|
||
private void processMessageTemplate(StringBuffer stringBuffer, MessageContext synCtx, String template) { | ||
try { | ||
stringBuffer.append(InlineExpressionUtil.processInLineSynapseExpressionTemplate(synCtx, template)); | ||
} catch (JaxenException e) { | ||
handleException("Failed to process the message template : " + template, e, synCtx); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean isContentAware() { | ||
if (logLevel == CUSTOM) { | ||
|
||
return isContentAware; | ||
} | ||
|
||
public void processTemplateAndSetContentAware() { | ||
|
||
if (logLevel == MESSAGE_TEMPLATE || logLevel == CUSTOM) { | ||
for (MediatorProperty property : properties) { | ||
if (property.getExpression() != null && property.getExpression().isContentAware()) { | ||
return true; | ||
isContentAware = true; | ||
return; | ||
} | ||
} | ||
return false; | ||
isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(messageTemplate); | ||
} else { | ||
isContentAware = true; | ||
} | ||
return true; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,6 @@ | |
|
||
import com.google.gson.JsonArray; | ||
import com.google.gson.JsonElement; | ||
import com.google.gson.JsonNull; | ||
import com.google.gson.JsonObject; | ||
import com.google.gson.JsonParser; | ||
import com.google.gson.JsonPrimitive; | ||
|
@@ -30,6 +29,8 @@ | |
import org.apache.synapse.MessageContext; | ||
import org.apache.synapse.SynapseException; | ||
import org.apache.synapse.config.xml.SynapsePath; | ||
import org.apache.synapse.util.xpath.SynapseExpression; | ||
import org.apache.synapse.util.xpath.SynapseExpressionUtils; | ||
import org.apache.synapse.util.xpath.SynapseJsonPath; | ||
import org.apache.synapse.util.xpath.SynapseXPath; | ||
import org.jaxen.JaxenException; | ||
|
@@ -49,6 +50,9 @@ public final class InlineExpressionUtil { | |
// Regex to identify expressions in inline text | ||
private static final Pattern EXPRESSION_PATTERN = Pattern.compile("(\\{[^\\s\",<>}\\]]+})"); | ||
|
||
// Regex to identify synapse expressions ${expression} in inline text | ||
private static final Pattern SYNAPSE_EXPRESSION_PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{(.+?)}"); | ||
|
||
private InlineExpressionUtil() { | ||
|
||
} | ||
|
@@ -197,4 +201,48 @@ private static boolean isValidXML(String stringToValidate) { | |
} | ||
return false; | ||
} | ||
|
||
/** | ||
* Checks whether inline template contains content aware synapse expressions. | ||
* Inline expressions will be denoted inside ${} | ||
* e.g.: ${var.var1}, ${payload.element.id} | ||
* | ||
* @param inlineText Inline text string | ||
* @return true if the string contains content aware inline synapse expressions, false otherwise | ||
*/ | ||
public static boolean isInlineSynapseExpressionsContentAware(String inlineText) { | ||
|
||
Matcher matcher = SYNAPSE_EXPRESSION_PLACEHOLDER_PATTERN.matcher(inlineText); | ||
while (matcher.find()) { | ||
// Extract the expression inside ${...} | ||
String expression = matcher.group(1); | ||
if (SynapseExpressionUtils.isSynapseExpressionContentAware(expression)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* Process the inline template and replace the synapse expressions with the resolved values | ||
* | ||
* @param synCtx Message Context | ||
* @param template Inline template | ||
* @return Processed inline template | ||
*/ | ||
public static String processInLineSynapseExpressionTemplate(MessageContext synCtx, String template) | ||
throws JaxenException { | ||
|
||
Matcher matcher = SYNAPSE_EXPRESSION_PLACEHOLDER_PATTERN.matcher(template); | ||
StringBuffer result = new StringBuffer(); | ||
while (matcher.find()) { | ||
// Extract the expression inside ${...} | ||
String placeholder = matcher.group(1); | ||
SynapseExpression expression = new SynapseExpression(placeholder); | ||
String replacement = expression.stringValueOf(synCtx); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if the stringValueOf fails we get the value "unknown" should we print a warn log outside the while loop saying processed template might have an incorrect result since evaluation of some expressions failed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We cannot distinguish the |
||
matcher.appendReplacement(result, Matcher.quoteReplacement(replacement)); | ||
} | ||
matcher.appendTail(result); | ||
return result.toString(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. | ||
* | ||
* WSO2 LLC. licenses this file to you under the Apache License, | ||
* Version 2.0 (the "License"); you may not use this file except | ||
* in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
package org.apache.synapse.util.xpath; | ||
|
||
import org.jaxen.JaxenException; | ||
|
||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
/** | ||
* Utility class for Synapse Expressions | ||
*/ | ||
public class SynapseExpressionUtils { | ||
|
||
/** | ||
* Checks whether the synapse expression is content aware | ||
* | ||
* @param synapseExpression synapse expression string | ||
* @return true if the synapse expression is content aware, false otherwise | ||
*/ | ||
public static boolean isSynapseExpressionContentAware(String synapseExpression) { | ||
|
||
// TODO : Need to improve the content aware detection logic | ||
if (synapseExpression.equals("payload") || synapseExpression.equals("$") | ||
|| synapseExpression.contains("payload.") || synapseExpression.contains("$.")) { | ||
return true; | ||
} else if (synapseExpression.contains("xpath(")) { | ||
// TODO change the regex to support xpath + variable syntax | ||
Pattern pattern = Pattern.compile("xpath\\(['\"](.*?)['\"]\\s*(,\\s*['\"](.*?)['\"])?\\)?"); | ||
Matcher matcher = pattern.matcher(synapseExpression); | ||
// Find all matches | ||
while (matcher.find()) { | ||
if (matcher.group(2) != null) { | ||
// evaluating xpath on a variable so not content aware | ||
continue; | ||
} | ||
String xpath = matcher.group(1); | ||
try { | ||
SynapseXPath synapseXPath = new SynapseXPath(xpath); | ||
if (synapseXPath.isContentAware()) { | ||
return true; | ||
} | ||
} catch (JaxenException e) { | ||
// Ignore the exception and continue | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why an additional new line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's added by the
wso2_code_style
for idea.