Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/azure-cli/azure/cli/command_modules/appservice/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -2371,6 +2371,39 @@
text: az webapp log deployment list --name MyWebApp --resource-group MyResourceGroup
"""

helps['webapp log startup'] = """
type: group
short-summary: View web app container startup logs.
long-summary: >
View startup logs written during container initialization for Linux web apps.
Use when a container fails to start, crashes on cold start, times out waiting
for a port, or returns HTTP 502/503 errors after deployment. These logs contain
platform lifecycle events and container stdout/stderr output.
"""

helps['webapp log startup list'] = """
type: command
short-summary: List all container startup log files for a web app.
examples:
- name: List all startup log files
text: az webapp log startup list --name MyWebApp --resource-group MyResourceGroup
- name: List only failure logs
text: az webapp log startup list --name MyWebApp --resource-group MyResourceGroup --outcome failure
"""

helps['webapp log startup show'] = """
type: command
short-summary: Show the content of a container startup log.
long-summary: By default, shows the most recent startup log (preferring a failure log when one exists for the latest date). Use --filename to view a specific log file, or --instance to scope the latest-log lookup to a specific worker. --filename and --instance are mutually exclusive.
examples:
- name: Show the latest startup log (prefers failures)
text: az webapp log startup show --name MyWebApp --resource-group MyResourceGroup
- name: Show a specific startup log file
text: az webapp log startup show --name MyWebApp --resource-group MyResourceGroup --filename 2026_04_13_lw0sdlwk000002_failure.log
- name: Show the latest startup log for a specific worker instance
text: az webapp log startup show --name MyWebApp --resource-group MyResourceGroup --instance lw0sdlwk000002
"""

helps['functionapp log'] = """
type: group
short-summary: Manage function app logs.
Expand Down
13 changes: 13 additions & 0 deletions src/azure-cli/azure/cli/command_modules/appservice/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,19 @@ def load_arguments(self, _):
c.argument('resource_group', arg_type=resource_group_name_type)
c.argument('slot', options_list=['--slot', '-s'], help="the name of the slot. Default to the productions slot if not specified")

with self.argument_context('webapp log startup') as c:
c.argument('name', arg_type=webapp_name_arg_type, id_part=None)
c.argument('resource_group', arg_type=resource_group_name_type)
c.argument('slot', options_list=['--slot', '-s'], help="the name of the slot. Default to the production slot if not specified")
c.argument('instance', options_list=['--instance'], help='Filter by worker instance name.')

with self.argument_context('webapp log startup list') as c:
c.argument('outcome', options_list=['--outcome'], help='Filter by startup outcome.',
arg_type=get_enum_type(['success', 'failure']))

with self.argument_context('webapp log startup show') as c:
Comment thread
faditawfik21 marked this conversation as resolved.
c.argument('filename', options_list=['--filename', '-f'], help='Name of a specific startup log file to display. If not specified, shows the latest log (preferring failures).')

with self.argument_context('functionapp log deployment show') as c:
c.argument('name', arg_type=functionapp_name_arg_type, id_part=None)
c.argument('resource_group', arg_type=resource_group_name_type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,10 @@ def load_command_table(self, _):
g.custom_show_command('show', 'show_deployment_log')
g.custom_command('list', 'list_deployment_logs')

with self.command_group('webapp log startup', is_preview=True) as g:
g.custom_command('list', 'list_startup_logs')
g.custom_show_command('show', 'show_startup_log')

with self.command_group('functionapp log deployment') as g:
g.custom_show_command('show', 'show_deployment_log')
g.custom_command('list', 'list_deployment_logs')
Expand Down
115 changes: 115 additions & 0 deletions src/azure-cli/azure/cli/command_modules/appservice/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -6313,6 +6313,111 @@ def list_deployment_logs(cmd, resource_group, name, slot=None):
return response.json() or []


def _ensure_linux_webapp_for_startup_logs(cmd, resource_group, name, slot=None):
client = web_client_factory(cmd.cli_ctx)
if slot:
app = client.web_apps.get_slot(resource_group, name, slot)
else:
app = client.web_apps.get(resource_group, name)
if app is None or not is_linux_webapp(app):
raise ArgumentUsageError(
"'az webapp log startup' is only supported for Linux web apps.")


def list_startup_logs(cmd, resource_group, name, slot=None, outcome=None, instance=None):
import requests

Comment thread
faditawfik21 marked this conversation as resolved.
_ensure_linux_webapp_for_startup_logs(cmd, resource_group, name, slot)

scm_url = _get_scm_url(cmd, resource_group, name, slot)
headers = get_scm_site_headers(cmd.cli_ctx, name, resource_group, slot)

params = {}
if outcome:
params['type'] = outcome
if instance:
params['instance'] = instance

url = '{}/api/startuplogs'.format(scm_url)
response = requests.get(url, headers=headers, params=params)

if response.status_code == 404:
if instance:
logger.warning(
"No startup logs found for instance '%s'. "
"Run 'az webapp log startup list' to see available instances.", instance)
else:
# TODO: remove rollout-aware wording after KuduLite/LWASv2 GA (see Phase 4 in feature memory).
logger.warning(
'Startup logs are not available for this app. '
'This feature requires a platform version that may not have rolled out to your app\'s region yet.')
return []
if response.status_code != 200:
raise CLIError("Failed to retrieve startup logs from '{}' with status code '{}' and reason '{}'".format(
url, response.status_code, response.reason))

result = response.json()
return result.get('files', result) if isinstance(result, dict) else result


def show_startup_log(cmd, resource_group, name, slot=None, filename=None, instance=None):
import requests

if filename and instance:
raise MutuallyExclusiveArgumentError(
'--filename and --instance cannot be used together. '
'--filename selects a specific log file; --instance scopes the latest-log lookup to a worker.')

_ensure_linux_webapp_for_startup_logs(cmd, resource_group, name, slot)

scm_url = _get_scm_url(cmd, resource_group, name, slot)
headers = get_scm_site_headers(cmd.cli_ctx, name, resource_group, slot)

if filename:
url = '{}/api/startuplogs/{}'.format(scm_url, quote(filename, safe=''))
else:
# Server-side selection: most recent date, prefers a failure log if one exists
# for that date, otherwise returns the success log for that date.
url = '{}/api/startuplogs?latest=true'.format(scm_url)
Comment thread
faditawfik21 marked this conversation as resolved.
if instance:
Comment thread
faditawfik21 marked this conversation as resolved.
url += '&instance={}'.format(quote(instance, safe=''))

response = requests.get(url, headers=headers)

if response.status_code == 404:
if filename:
logger.warning('Startup log file \'%s\' was not found.', filename)
elif instance:
logger.warning(
"No startup logs found for instance '%s'. "
"Run 'az webapp log startup list' to see available instances.", instance)
else:
# TODO: remove rollout-aware wording after KuduLite/LWASv2 GA (see Phase 4 in feature memory).
logger.warning(
'Startup logs are not available for this app. '
'This feature requires a platform version that may not have rolled out to your app\'s region yet.')
Comment thread
faditawfik21 marked this conversation as resolved.
return None
if response.status_code != 200:
raise CLIError("Failed to retrieve startup log from '{}' with status code '{}' and reason '{}'".format(
url, response.status_code, response.reason))

content_type = response.headers.get('Content-Type', '')
if 'text/plain' in content_type:
# Raw log content — return metadata from headers along with content
log_content = response.text
metadata = {}
for header_name in ['X-StartupLog-Filename', 'X-StartupLog-Date', 'X-StartupLog-Instance',
'X-StartupLog-Outcome']:
value = response.headers.get(header_name)
if value:
key = header_name.replace('X-StartupLog-', '').lower()
metadata[key] = value
metadata['content'] = log_content
return metadata

return response.json()


def config_slot_auto_swap(cmd, resource_group_name, webapp, slot, auto_swap_slot=None, disable=None):
client = web_client_factory(cmd.cli_ctx)
site_config = client.web_apps.get_configuration_slot(resource_group_name, webapp, slot)
Expand Down Expand Up @@ -9237,6 +9342,11 @@ def _poll_deployment_runtime_status(cmd, resource_group_name, webapp_name, slot,
if failure_logs is not None and len(failure_logs) > 0:
failure_logs = failure_logs[0]
error_text += "Please check the runtime logs for more info: {}\n".format(failure_logs)
tip_cmd = "az webapp log startup show -n {} -g {}".format(webapp_name, resource_group_name)
if slot:
tip_cmd += " --slot {}".format(slot)
error_text += ("TIP: Run '{}' "
"to view container startup logs.\n").format(tip_cmd)
if site_started_partially:
logger.warning(error_text)
break
Expand Down Expand Up @@ -9281,6 +9391,11 @@ def _poll_deployment_runtime_status(cmd, resource_group_name, webapp_name, slot,
deployment_properties.get('numberOfInstancesInProgress'),
deployment_properties.get('numberOfInstancesSuccessful'),
deployment_properties.get('numberOfInstancesFailed'))
tip_cmd = "az webapp log startup show -n {} -g {}".format(webapp_name, resource_group_name)
Comment thread
faditawfik21 marked this conversation as resolved.
if slot:
tip_cmd += " --slot {}".format(slot)
error_text += ("\nTIP: Run '{}' "
"to view container startup logs.").format(tip_cmd)
raise CLIError(error_text)
return response_body

Expand Down
Loading
Loading