Skip to content

Commit 71645db

Browse files
committed
[AppService] az webapp log startup: Add commands to list and view Linux container startup logs
1 parent faa4a92 commit 71645db

5 files changed

Lines changed: 386 additions & 1 deletion

File tree

src/azure-cli/azure/cli/command_modules/appservice/_help.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2365,6 +2365,33 @@
23652365
text: az webapp log deployment list --name MyWebApp --resource-group MyResourceGroup
23662366
"""
23672367

2368+
helps['webapp log startup'] = """
2369+
type: group
2370+
short-summary: Manage web app container startup logs.
2371+
long-summary: View startup logs written during container initialization for Linux web apps. These logs contain platform lifecycle events and container stdout/stderr output from each cold start attempt.
2372+
"""
2373+
2374+
helps['webapp log startup list'] = """
2375+
type: command
2376+
short-summary: List all container startup log files for a web app.
2377+
examples:
2378+
- name: List all startup log files
2379+
text: az webapp log startup list --name MyWebApp --resource-group MyResourceGroup
2380+
- name: List only failure logs
2381+
text: az webapp log startup list --name MyWebApp --resource-group MyResourceGroup --outcome failure
2382+
"""
2383+
2384+
helps['webapp log startup show'] = """
2385+
type: command
2386+
short-summary: Show the content of a container startup log.
2387+
long-summary: By default, shows the most recent startup log, preferring failure logs. Use --filename to view a specific log file.
2388+
examples:
2389+
- name: Show the latest startup log (prefers failures)
2390+
text: az webapp log startup show --name MyWebApp --resource-group MyResourceGroup
2391+
- name: Show a specific startup log file
2392+
text: az webapp log startup show --name MyWebApp --resource-group MyResourceGroup --filename 2026_04_13_lw0sdlwk000002_failure.log
2393+
"""
2394+
23682395
helps['functionapp log'] = """
23692396
type: group
23702397
short-summary: Manage function app logs.

src/azure-cli/azure/cli/command_modules/appservice/_params.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,20 @@ def load_arguments(self, _):
780780
c.argument('resource_group', arg_type=resource_group_name_type)
781781
c.argument('slot', options_list=['--slot', '-s'], help="the name of the slot. Default to the productions slot if not specified")
782782

783+
with self.argument_context('webapp log startup list') as c:
784+
c.argument('name', arg_type=webapp_name_arg_type, id_part=None)
785+
c.argument('resource_group', arg_type=resource_group_name_type)
786+
c.argument('slot', options_list=['--slot', '-s'], help="the name of the slot. Default to the production slot if not specified")
787+
c.argument('outcome', options_list=['--outcome'], help='Filter by startup outcome.',
788+
arg_type=get_enum_type(['success', 'failure']))
789+
c.argument('instance', options_list=['--instance'], help='Filter by worker instance name.')
790+
791+
with self.argument_context('webapp log startup show') as c:
792+
c.argument('name', arg_type=webapp_name_arg_type, id_part=None)
793+
c.argument('resource_group', arg_type=resource_group_name_type)
794+
c.argument('slot', options_list=['--slot', '-s'], help="the name of the slot. Default to the production slot if not specified")
795+
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).')
796+
783797
with self.argument_context('functionapp log deployment show') as c:
784798
c.argument('name', arg_type=functionapp_name_arg_type, id_part=None)
785799
c.argument('resource_group', arg_type=resource_group_name_type)

src/azure-cli/azure/cli/command_modules/appservice/commands.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ def load_command_table(self, _):
246246
g.custom_show_command('show', 'show_deployment_log')
247247
g.custom_command('list', 'list_deployment_logs')
248248

249+
with self.command_group('webapp log startup', is_preview=True) as g:
250+
g.custom_command('list', 'list_startup_logs')
251+
g.custom_show_command('show', 'show_startup_log')
252+
249253
with self.command_group('functionapp log deployment') as g:
250254
g.custom_show_command('show', 'show_deployment_log')
251255
g.custom_command('list', 'list_deployment_logs')

src/azure-cli/azure/cli/command_modules/appservice/custom.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5597,6 +5597,76 @@ def list_deployment_logs(cmd, resource_group, name, slot=None):
55975597
return response.json() or []
55985598

55995599

5600+
def list_startup_logs(cmd, resource_group, name, slot=None, outcome=None, instance=None):
5601+
import requests
5602+
5603+
scm_url = _get_scm_url(cmd, resource_group, name, slot)
5604+
headers = get_scm_site_headers(cmd.cli_ctx, name, resource_group, slot)
5605+
5606+
params = {}
5607+
if outcome:
5608+
params['type'] = outcome
5609+
if instance:
5610+
params['instance'] = instance
5611+
5612+
url = '{}/api/startuplogs'.format(scm_url)
5613+
response = requests.get(url, headers=headers, params=params)
5614+
5615+
if response.status_code == 404:
5616+
logger.warning(
5617+
'Startup logs are not available for this app. '
5618+
'This feature requires a platform version that may not have rolled out to your app\'s region yet.')
5619+
return []
5620+
if response.status_code != 200:
5621+
raise CLIError("Failed to retrieve startup logs from '{}' with status code '{}' and reason '{}'".format(
5622+
url, response.status_code, response.reason))
5623+
5624+
result = response.json()
5625+
return result.get('files', result) if isinstance(result, dict) else result
5626+
5627+
5628+
def show_startup_log(cmd, resource_group, name, slot=None, filename=None):
5629+
import requests
5630+
5631+
scm_url = _get_scm_url(cmd, resource_group, name, slot)
5632+
headers = get_scm_site_headers(cmd.cli_ctx, name, resource_group, slot)
5633+
5634+
if filename:
5635+
url = '{}/api/startuplogs/{}'.format(scm_url, quote(filename, safe=''))
5636+
else:
5637+
url = '{}/api/startuplogs?latest=true'.format(scm_url)
5638+
5639+
response = requests.get(url, headers=headers)
5640+
5641+
if response.status_code == 404:
5642+
if filename:
5643+
logger.warning('Startup log file \'%s\' was not found.', filename)
5644+
else:
5645+
logger.warning(
5646+
'Startup logs are not available for this app. '
5647+
'This feature requires a platform version that may not have rolled out to your app\'s region yet.')
5648+
return None
5649+
if response.status_code != 200:
5650+
raise CLIError("Failed to retrieve startup log from '{}' with status code '{}' and reason '{}'".format(
5651+
url, response.status_code, response.reason))
5652+
5653+
content_type = response.headers.get('Content-Type', '')
5654+
if 'text/plain' in content_type:
5655+
# Raw log content — return metadata from headers along with content
5656+
log_content = response.text
5657+
metadata = {}
5658+
for header_name in ['X-StartupLog-Filename', 'X-StartupLog-Date', 'X-StartupLog-Instance',
5659+
'X-StartupLog-Outcome']:
5660+
value = response.headers.get(header_name)
5661+
if value:
5662+
key = header_name.replace('X-StartupLog-', '').lower()
5663+
metadata[key] = value
5664+
metadata['content'] = log_content
5665+
return metadata
5666+
5667+
return response.json()
5668+
5669+
56005670
def config_slot_auto_swap(cmd, resource_group_name, webapp, slot, auto_swap_slot=None, disable=None):
56015671
client = web_client_factory(cmd.cli_ctx)
56025672
site_config = client.web_apps.get_configuration_slot(resource_group_name, webapp, slot)
@@ -8521,6 +8591,8 @@ def _poll_deployment_runtime_status(cmd, resource_group_name, webapp_name, slot,
85218591
if failure_logs is not None and len(failure_logs) > 0:
85228592
failure_logs = failure_logs[0]
85238593
error_text += "Please check the runtime logs for more info: {}\n".format(failure_logs)
8594+
error_text += ("TIP: Run 'az webapp log startup show -n {} -g {}' "
8595+
"to view container startup logs.\n").format(webapp_name, resource_group_name)
85248596
if site_started_partially:
85258597
logger.warning(error_text)
85268598
break
@@ -8565,6 +8637,8 @@ def _poll_deployment_runtime_status(cmd, resource_group_name, webapp_name, slot,
85658637
deployment_properties.get('numberOfInstancesInProgress'),
85668638
deployment_properties.get('numberOfInstancesSuccessful'),
85678639
deployment_properties.get('numberOfInstancesFailed'))
8640+
error_text += ("\nTIP: Run 'az webapp log startup show -n {} -g {}' "
8641+
"to view container startup logs.").format(webapp_name, resource_group_name)
85688642
raise CLIError(error_text)
85698643
return response_body
85708644

0 commit comments

Comments
 (0)