How to get Web App for Container logs into Azure Monitor (AppServiceConsoleLogs)

0
How to get Windows Container logs

If you run a Windows container on Azure App Service and your application’s logs never show up in Log Analytics, this guide covers the two things that actually cause it. Both are easy to miss, and neither is in the documentation.

Everything below was tested against a real Windows container app. I’ve also listed what does not help, so you don’t waste time on it.

Running a Linux container? Almost none of this applies. Jump to Linux Containers Are a Different Story at the end.

This is the Source documentation we will be following. If things change I would look to this for guidance. Azure App Service monitoring data reference

Prerequisites

  • An Azure App Service running a Windows container (kind = app,container,windows)
  • A Log Analytics workspace
  • A container image you can rebuild (you may need to change one line in the Dockerfile)
  • An app that writes to stdout. A normal ASP.NET Core ILogger app is fine

Note: Windows containers require a Premium v3 plan (P1v3 or larger). That’s a hosting requirement, not a logging one.

The Short Version

  1. Your image must not have an ENTRYPOINT. App Service has to start your process.
  2. Query both ResultDescription and Message. A Windows container writes to Message.

If logs are missing entirely, it’s almost always #1. If the app looks healthy but you can’t find your messages, it’s #2.

Setting Up the Image

This is the part that catches people out.

If your Dockerfile has an exec-form ENTRYPOINT, App Service’s startup command is passed as CMD, and Docker appends CMD as arguments to ENTRYPOINT instead of replacing it. Your ENTRYPOINT still wins, App Service never launches your process, and its log collector never attaches.

The result: AppServiceConsoleLogs stays completely empty. Not even container startup messages.

Change this:

Just delete the ENTRYPOINT line:

Rebuild and push. If you don’t have Docker locally, you can build in Azure:

Setting Up the App

Open the app in the portal > Configuration > General settings > Startup Command, and enter the command that runs your app:

Note: the path is the one inside your image (the WORKDIR you used), not a path on the App Service file system.

Then restart the app.

Note: App Service splits the startup command on whitespace and does not honour quotes. If your command needs quotes or arguments containing spaces, it will break in confusing ways.

Setting Up the Diagnostic Setting

Open the app in the portal > Monitoring > Diagnostic settings > Add diagnostic setting.

Tick the categories you want and send them to your Log Analytics workspace:

  • AppServiceConsoleLogs: stdout / stderr
  • AppServiceAppLogs: application logs
  • AppServiceHTTPLogs: web server logs
  • AppServicePlatformLogs: container operation logs

That is genuinely all the configuration required. Save it, then browse your app a few times to generate some log lines.

Validating It worked

Give it 5–10 minutes for ingestion, then run this in the workspace. Use coalesce, this is the second thing that catches people out:

A Windows container puts your message in the Message column and leaves ResultDescription empty. A Windows code app does the exact opposite. The portal’s default queries and nearly every KQL sample you’ll find online. Only read ResultDescription, so a container’s logs look missing even when they arrived.

Both columns are documented, so neither is wrong; nothing just tells you which one you’ll get.

And for console output:

You should see your application’s log lines in both.

Things That Will Confuse You

Your log line appears twice. One ILogger.LogError() produces a row in AppServiceAppLogs and a row in AppServiceConsoleLogs. You’re paying ingestion on both.

The severity is wrong in one of them. Error is preserved in AppServiceAppLogs, but flattened to Informational in AppServiceConsoleLogs. Trust the AppLogs copy for severity.

AppServiceAppLogs looks like it’s working when it isn’t. A Windows container always emits platform reverse-proxy rows that look like real application logging:

Those appear whether or not your app logs anything. Filter them out before concluding logging works:

The console text has odd formatting. The AppServiceConsoleLogs copy is the raw console output, including the ASP.NET Core formatter’s leading spaces and a trailing \r\n. Exact-match filters will miss it.

What Does NOT Fix This

I tested each of these on a Windows container that wasn’t exporting logs. None of them made any difference, so don’t bother:

  • App Service logs > Application logging (Filesystem): no effect on a container.
  • WEBSITES_ENABLE_APP_SERVICE_STORAGE=true: no effect on logging.
  • Generating more traffic. There is no volume threshold. I pushed roughly 8,000 log lines through a misconfigured app and got nothing.
  • Checking for console.log files in Kudu. This is the most misleading one. Those files are written by a completely separate pipeline from diagnostic settings. The file existing does not mean the export is working, and its absence doesn’t mean it’s broken. I confirmed this by making every log file appear in Kudu and watching Log Analytics stay empty.

How to Tell Which Problem You Have

Check whether AppServiceConsoleLogs has any rows at all for your app:

  • Zero rows, not even container startup messages: the collector never attached. That’s the ENTRYPOINT problem. Rebuild the image without it.
  • Rows exist but you can’t find your messages: the collector is fine. That’s the column problem. Use coalesce(ResultDescription, Message).

Linux Containers Are a Different Story

I ran the same experiment on Linux. Same application, same Dockerfile pattern, same workspace, same queries. Nearly every conclusion above is Windows specific.

On Linux the whole setup is: add the diagnostic setting. That is it. I tested an app with Always On off, no startup command, no WEBSITES_PORT, and no app settings at all, and its logs exported fine.

Do not delete your ENTRYPOINT on Linux. I ran two identical apps side by side, one with an exec-form ENTRYPOINT and one relying on a startup command. Both exported the same logs. The Windows fix does nothing here. Linux captures container stdout through Docker’s logging driver, which does not care how the process started.

The Linux gotcha is a different one: AppServiceAppLogs is always empty. A normal stdout app on Linux puts everything in AppServiceConsoleLogs. The AppServiceAppLogs table still gets created by your diagnostic setting, so it looks like it should have data. It just never will. I confirmed zero rows. Getting data into it requires a Java image or the x-ms-applog: stdout prefix.

So on Linux, query this:

The differences, side by side:

  • Minimum setup: Windows needs the diagnostic setting plus no ENTRYPOINT. Linux needs only the diagnostic setting.
  • AppServiceAppLogs: populated on Windows, always empty on Linux for stdout apps.
  • Your message lands in: Message on Windows, ResultDescription on Linux.
  • Rows per log call: 2 on Windows, so double ingestion. 1 on Linux.
  • Plan tier: P1v3 forced by Windows container hosting. B1 is fine on Linux.

One thing that is the same: the level gets flattened to Informational in AppServiceConsoleLogs on both platforms, so do not rely on it for severity.

About Author

Leave a Reply

Your email address will not be published. Required fields are marked *