最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - Print function not working without flush=True when used with the While loop - Stack Overflow

programmeradmin1浏览0评论

Is there some known issue where the Python environment for Azure Runbooks does not like the while loop function in conjunction with the print function without appending flush=True?

I have not seen one print statement returned when the word while has been included in the main function.

This is designed to send an alert whenever the status of my Azure VM changes. (This will be via email, but for ease, I have just included print statements...which should work)

Remove the while functionality, and all the print statements appear.

It's such a silly situation. Even the print("Can you see this message....") nor the print("Entering loop...") does not print. These print statements are not even printing in the while loop so it should print even if there is an issue with the execution of the while loop (which there is not). I would show you via debug printing but if the thing actually printed like I told it to, then you would be able to see.

My blood pressure seriously is rising because of this. The compute_client is authenticated, and it returns the correct vm_name, so why - whenever I include the while loop - does it have a hissy fit?

I am so angry with this.

import time, random, smtplib, inspect, string
from datetime import datetime
from email.mime.text import MIMEText
from azuremon.credentials import ServicePrincipalCredentials
from azure.mgmtpute import ComputeManagementClient

# Azure setup
subscription_id = 'xxx'  
resource_group_name = 'xxx'  
vm_name = 'xxx'  

from azure.core.exceptions import ClientAuthenticationError

# Authentication of Azure's Service Principal
def service_principal_authentication():
    """Checks the Authentication of Azure's Service Principal """
    print("Authenticating Service Principal....")
    try:
        credentials = ServicePrincipalCredentials(
            client_id='xxx',
            secret='xxx',
            tenant='xxx'
        )
        print("Service Principal Authenticity Verified")
        return ComputeManagementClient(credentials, subscription_id)
    except Exception as e:
        print(f"There was an error with the authenticating the Service Principal: {e}")
    except ClientAuthenticationError as e:
        print(f"Client Authentication Error {e}")

# Email setup
sender_email = 'xxx'  
receiver_email = 'xxxx' 
smtp_server = 'xxx'   
smtp_port = 587
smtp_password = 'xxx'  

def send_notification(subject, body):
    """Send an email notification."""
    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = sender_email
    msg['To'] = receiver_email

    try:
        with smtplib.SMTP(smtp_server, smtp_port) as server:
            server.starttls()
            server.login(sender_email, smtp_password)
            server.sendmail(sender_email, receiver_email, msg.as_string())
            print("Email sent successfully!")
    except Exception as e:
        print(f"{e} in ", inspect.stack()[0].function)

def get_vm_status(compute_client):
    """Retrieve the current status of the VM."""
    print("Retrieving VM status......")
    try:
        # Explicitly request the instance view
        vm = compute_client.virtual_machines.get(resource_group_name, vm_name, expand='instanceView')
        
        # Check if instance view is available
        if vm.instance_view:
            print(f"Can you see this message? {inspect.stack()[0].function}")
            return vm.instance_view.statuses[1].code  # Assuming the status is at index 1
        else:
            print("Instance view is not available.")
            return None
        
    except ClientAuthenticationError as e:
        print(f"There was a client authentication error {e}")
    except Exception as e:
        print(f"Error retrieving VM status: {e}, in function {inspect.stack()[0].function}")

def generate_incident_reference_number():
    incident_timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S")
    incident_number = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10))
    return f"INC{incident_timestamp}{incident_number}"

def log_to_azure_monitor():
    pass

def main():
    print("Entering loop.....",flush=True)
    while True:
        compute_client = service_principal_authentication()
        previous_vm_status = None
        current_vm_status = get_vm_status(compute_client)

        if current_vm_status != previous_vm_status:
            incident_number = generate_incident_reference_number()
            print(f"This has changed {current_vm_status} - {previous_vm_status} - {incident_number}", flush=True)
        else:
            print(f"This has remained the same {current_vm_status}", flush=True)
        previous_vm_status = current_vm_status
        time.sleep(10)

if __name__ == "__main__":
    main()

Is there some known issue where the Python environment for Azure Runbooks does not like the while loop function in conjunction with the print function without appending flush=True?

I have not seen one print statement returned when the word while has been included in the main function.

This is designed to send an alert whenever the status of my Azure VM changes. (This will be via email, but for ease, I have just included print statements...which should work)

Remove the while functionality, and all the print statements appear.

It's such a silly situation. Even the print("Can you see this message....") nor the print("Entering loop...") does not print. These print statements are not even printing in the while loop so it should print even if there is an issue with the execution of the while loop (which there is not). I would show you via debug printing but if the thing actually printed like I told it to, then you would be able to see.

My blood pressure seriously is rising because of this. The compute_client is authenticated, and it returns the correct vm_name, so why - whenever I include the while loop - does it have a hissy fit?

I am so angry with this.

import time, random, smtplib, inspect, string
from datetime import datetime
from email.mime.text import MIMEText
from azuremon.credentials import ServicePrincipalCredentials
from azure.mgmtpute import ComputeManagementClient

# Azure setup
subscription_id = 'xxx'  
resource_group_name = 'xxx'  
vm_name = 'xxx'  

from azure.core.exceptions import ClientAuthenticationError

# Authentication of Azure's Service Principal
def service_principal_authentication():
    """Checks the Authentication of Azure's Service Principal """
    print("Authenticating Service Principal....")
    try:
        credentials = ServicePrincipalCredentials(
            client_id='xxx',
            secret='xxx',
            tenant='xxx'
        )
        print("Service Principal Authenticity Verified")
        return ComputeManagementClient(credentials, subscription_id)
    except Exception as e:
        print(f"There was an error with the authenticating the Service Principal: {e}")
    except ClientAuthenticationError as e:
        print(f"Client Authentication Error {e}")

# Email setup
sender_email = 'xxx'  
receiver_email = 'xxxx' 
smtp_server = 'xxx'   
smtp_port = 587
smtp_password = 'xxx'  

def send_notification(subject, body):
    """Send an email notification."""
    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = sender_email
    msg['To'] = receiver_email

    try:
        with smtplib.SMTP(smtp_server, smtp_port) as server:
            server.starttls()
            server.login(sender_email, smtp_password)
            server.sendmail(sender_email, receiver_email, msg.as_string())
            print("Email sent successfully!")
    except Exception as e:
        print(f"{e} in ", inspect.stack()[0].function)

def get_vm_status(compute_client):
    """Retrieve the current status of the VM."""
    print("Retrieving VM status......")
    try:
        # Explicitly request the instance view
        vm = compute_client.virtual_machines.get(resource_group_name, vm_name, expand='instanceView')
        
        # Check if instance view is available
        if vm.instance_view:
            print(f"Can you see this message? {inspect.stack()[0].function}")
            return vm.instance_view.statuses[1].code  # Assuming the status is at index 1
        else:
            print("Instance view is not available.")
            return None
        
    except ClientAuthenticationError as e:
        print(f"There was a client authentication error {e}")
    except Exception as e:
        print(f"Error retrieving VM status: {e}, in function {inspect.stack()[0].function}")

def generate_incident_reference_number():
    incident_timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S")
    incident_number = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10))
    return f"INC{incident_timestamp}{incident_number}"

def log_to_azure_monitor():
    pass

def main():
    print("Entering loop.....",flush=True)
    while True:
        compute_client = service_principal_authentication()
        previous_vm_status = None
        current_vm_status = get_vm_status(compute_client)

        if current_vm_status != previous_vm_status:
            incident_number = generate_incident_reference_number()
            print(f"This has changed {current_vm_status} - {previous_vm_status} - {incident_number}", flush=True)
        else:
            print(f"This has remained the same {current_vm_status}", flush=True)
        previous_vm_status = current_vm_status
        time.sleep(10)

if __name__ == "__main__":
    main()
Share Improve this question edited Jan 19 at 12:52 TheFlyingPrussian asked Jan 18 at 15:22 TheFlyingPrussianTheFlyingPrussian 235 bronze badges 4
  • 1 Assuming STDOUT wasn't redirected elsewhere, the only way this could print nothing is if get_vm_status is blocking forever. Is "Retrieving VM status......" printing? If you put a print at the end of that function right before the return, does that print? – Carcigenicate Commented Jan 18 at 15:55
  • @Carcigenicate Neither is printing. Code updated to your suggestion so you can see where I have placed the additional print statements. – TheFlyingPrussian Commented Jan 19 at 11:55
  • @TheFlyingPrussian, Try adding print statements right before each function call and after each block of code inside get_vm_status. – Suresh Chikkam Commented Jan 20 at 10:47
  • If you can set the PYTHONUNBUFFERED environment variable for the run, that might help. – AKX Commented Feb 18 at 17:02
Add a comment  | 

2 Answers 2

Reset to default 0

As mentioned, Azure Runbooks have output buffering, and this can sometimes prevent the immediate display of print statements within loops.

  • Even though you added flush=True to print, the loop might be running so continuously that the output buffering is not flushed in time. Try adding additional flush calls, or consider logging instead of using print.

  • Remove the while True loop and test with a finite loop or a time-limited loop to see if you can isolate the issue.

Neither is printing. Code updated to your suggestion so you can see where I have placed the additional print statements.

The script may be blocking before reaching the get_vm_status function or while executing the function itself.

Start by adding a print statement right before calling get_vm_status to check if it's being called at all. Then, in the get_vm_status function, place prints just before each major operation to track its execution.

Updated code:

import time
import random
import smtplib
import inspect
import string
from datetime import datetime
from email.mime.text import MIMEText
from azuremon.credentials import ServicePrincipalCredentials
from azure.mgmtpute import ComputeManagementClient
from azure.core.exceptions import ClientAuthenticationError

# Azure setup
subscription_id = 'xxx'  
resource_group_name = 'xxx'  
vm_name = 'xxx'  

# Authentication of Azure's Service Principal
def service_principal_authentication():
    """Checks the Authentication of Azure's Service Principal """
    print("Authenticating Service Principal....")
    try:
        credentials = ServicePrincipalCredentials(
            client_id='xxx',
            secret='xxx',
            tenant='xxx'
        )
        print("Service Principal Authenticity Verified")
        return ComputeManagementClient(credentials, subscription_id)
    except Exception as e:
        print(f"There was an error with the authenticating the Service Principal: {e}")
    except ClientAuthenticationError as e:
        print(f"Client Authentication Error {e}")

# Email setup
sender_email = 'xxx'  
receiver_email = 'xxxx' 
smtp_server = 'xxx'   
smtp_port = 587
smtp_password = 'xxx'  

def send_notification(subject, body):
    """Send an email notification."""
    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = sender_email
    msg['To'] = receiver_email

    try:
        with smtplib.SMTP(smtp_server, smtp_port) as server:
            server.starttls()
            server.login(sender_email, smtp_password)
            server.sendmail(sender_email, receiver_email, msg.as_string())
            print("Email sent successfully!")
    except Exception as e:
        print(f"{e} in ", inspect.stack()[0].function)

def get_vm_status(compute_client):
    """Retrieve the current status of the VM."""
    print("Entering get_vm_status function.....", flush=True)
    try:
        print("Retrieving VM status......", flush=True)
        # Explicitly request the instance view
        vm = compute_client.virtual_machines.get(resource_group_name, vm_name, expand='instanceView')
        
        # Check if instance view is available
        if vm.instance_view:
            print(f"Can you see this message? {inspect.stack()[0].function}", flush=True)
            return vm.instance_view.statuses[1].code  # Assuming the status is at index 1
        else:
            print("Instance view is not available.", flush=True)
            return None
        
    except ClientAuthenticationError as e:
        print(f"There was a client authentication error {e}", flush=True)
    except Exception as e:
        print(f"Error retrieving VM status: {e}, in function {inspect.stack()[0].function}", flush=True)

def generate_incident_reference_number():
    incident_timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S")
    incident_number = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10))
    return f"INC{incident_timestamp}{incident_number}"

def log_to_azure_monitor():
    pass

def main():
    print("Entering loop.....", flush=True)
    while True:
        print("Before calling get_vm_status....", flush=True)  # Debug print before calling the function
        compute_client = service_principal_authentication()
        previous_vm_status = None
        current_vm_status = get_vm_status(compute_client)

        if current_vm_status != previous_vm_status:
            incident_number = generate_incident_reference_number()
            print(f"This has changed {current_vm_status} - {previous_vm_status} - {incident_number}", flush=True)
        else:
            print(f"This has remained the same {current_vm_status}", flush=True)
        previous_vm_status = current_vm_status
        time.sleep(10)

if __name__ == "__main__":
    main()
  • If "Before calling get_vm_status...." doesn’t appear, the issue lies in the initialization of the compute_client or the service_principal_authentication() method.
  • If "Retrieving VM status......" doesn’t appear, the issue is in the API call to retrieve the VM status.
  • If "Can you see this message?" doesn’t print, the function may not be returning or completing as expected.

Refreshing the workstreams in Azure runbooks will return all print statements. As a precaution, append flush=True to all print statements, as they are not printed automatically in some cases.

Ridiculous in my opinion but we have to work with the system architecture we're provided with.

发布评论

评论列表(0)

  1. 暂无评论