I've deployed a queue triggered azure function with Java in Azure. I've added logback-classic
and lombok
in pom.xml
for logging.
But the logs are not displayed on the function's monitor > invocation details
or the log-streaming service
in portal.
But I could see the logs written with context.getLogger()
. The logs writter with logback logger is not visible. Please let me know how to check my logs in function invocation.
Following is the queue triggerred azure function handle
public class QueueHandlerFunction {
@FunctionName("queuetriggertest")
public void queueMessageHandler(@QueueTrigger(name = "msg",
queueName = "my-test-queue", connection = "MyQStorage") final String payload,
final ExecutionContext context) {
//Logs with this logger is visible
context.getLogger().info("Received Message From my-test-queue : " + payload);
MySampleService.handleQueueMessage(payload);
}
}
Following is the MySampleService
class with lombok logger
@Slf4j
public class MySampleService {
public static void handleQueueMessage(final String payload) {
log.info("<<<<<<<<<<<< INSIDE THE SERVICE HANDLE >>>>>>>>>>>>");
if (StringUtils.isNotBlank(payload)) {
log.info("Received Payload : {}", payload); //This log not available
// TODO Work with incoming payload
} else {
log.info("Message payload is Blank."); //This log not available
}
}
}
Following is he logback.xml
placed in the resources folder of the maven project.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{E MMM dd yyyy hh:mm:ss a} [%thread] %-5level %logger{36}
- %msg%n</pattern>
</encoder>
</appender>
<logger name="com.howayig.test" level="INFO" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
And I've the following dependencies in the pom.xml
<dependencies>
<dependency>
<groupId>com.microsoft.azure.functions</groupId>
<artifactId>azure-functions-java-library</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
</dependencies>
EDIT: Attached portal screenshot for the function invocation logs...
EDIT 2: Added screenshots of local execution and deployed one in portal.
Logs in command prompt when is executed locally
Live streaming console service of the function from the portal for a new message in queue
Invocation details of the function from the portal for a new message in queue
None of the logging framework works other than java.util.logging till this date.
I have tried with log4j2, but logs don't come up in invocations details and hence they don't show up in Application Insights query either.
But Log4j2 logs appear under "Log stream" section of any of your Functions Apps. But again, that's not really helpful.
If you have already built-in application with some other logging framework, then either you need to change all of your logging to java.util.logging or do below.
Create below 2 custom classes in a separate maven module and include that to all of your function modules. Have same package name as the framework that you are using. In my case its "org.apache.logging.log4j"
They are not perfectly built custom classes. But this works.
package org.apache.logging.log4j;
public class LogManager {
static Logger logger = new Logger();
public static Logger getLogger() {
return logger;
}
public static void setLogger(Logger logger1) {
logger = logger1;
}
public static Logger getLogger(Class<?> class1) {
return logger;
}
public static Logger getLogger(String name) {
return logger;
}
}
package org.apache.logging.log4j;
import java.util.logging.Level;
public class Logger {
private java.util.logging.Logger logger;
public void setLogger(java.util.logging.Logger logger) {
this.logger = logger;
}
public void debug(Object... obj) {
printLog(obj, Level.FINE);
}
public void info(Object... obj) {
printLog(obj, Level.INFO);
}
public void error(Object... obj) {
printLog(obj, Level.SEVERE);
}
public void log(Object level, Object... obj) {
printLog(obj, Level.FINEST);
}
public void warn(Object... obj) {
printLog(obj, Level.WARNING);
}
private void printLog(Object[] obj, Level level) {
if (obj != null) {
String logString = obj[0] != null ? obj[0].toString() : "";
if (obj.length > 1) {
for (int i = 1; i < obj.length; i++) {
if (obj[i] != null) {
logString = logString.replaceFirst("\\{}", obj[i].toString());
}
}
}
logger.log(level, logString);
}
}
}
Then you can set your custom logger using Azure's Execution Context.
// LOG var Global to class
private final Logger LOG = LogManager.getLogger(BgdInfoAnalyticsHandler.class);
@FunctionName("func-name-fn")
public void run(
@ServiceBusQueueTrigger(name = "TriggerName", queueName = "sbq-use-queue-name", connection = "AzureWebJobsServiceBus") String input,
ExecutionContext context) {
LOG.setLogger(context.getLogger());
LogManager.setLogger(LOG);
String fnInput = HostServiceUtil.getBlobData(input);
LOG.info("fnInput : {} ", fnInput);
invokeService(fnInput);
}
Once this Logger is initiated/set in the entry point of your run method with Azure's ExecutionContext logger. You get this logger from any other class by doing LogManager.getLogger (Custom Class) as it is static.
Note: Static vars are being shared by different invocations or functions (if they resides in same function app)
Then you can do query in Application Insights as below:
union traces
| union exceptions | union requests
// | where timestamp > ago(2d)
// | where cloud_RoleName =~ 'fun-use-function-app-name' and operation_Name =~ 'function-name-fn' //and operation_Id =~ "7303edd79433b0468f934c80a88e5f77"
// | where innermostMessage contains "Exception" or message contains "Exception"
| project timestamp, message = iff(message != '', message,
iff(innermostMessage != '', innermostMessage, customDimensions.['prop__{OriginalFormat}'])), logLevel = customDimensions.['LogLevel']
, operation_Name, operation_Id, cloud_RoleName, invocationId=customDimensions['InvocationId']
| order by timestamp asc
| take 3000
You can also see Failure/Exception under: ApplicationInsights > Investigate section > Failures
It's now available via distributed tracing. You can view richer data from your function applications pertaining to the following requests, dependencies, logs and metrics.
All you need is:
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>applicationinsights-core</artifactId>
<version>2.6.0</version>
</dependency>
{
"instrumentationSettings": {
"connectionString": "InstrumentationKey=00000000-0000-0000-0000-000000000000"
}
}
private static final TelemetryClient telemetryClient = new TelemetryClient();
telemetryClient.trackTrace(message, SeverityLevel.Warning, properties);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With