与 While 循环一起使用时,如果没有flush=True,打印函数将无法工作

问题描述 投票:0回答:1

是否存在一些已知问题,即 Azure Runbooks 的 Python 环境不喜欢将

while
循环函数与
print
函数结合使用而不附加
flush=True

while
一词包含在
main
函数中时,我没有看到返回任何打印语句。

这旨在每当我的 Azure VM 的状态发生变化时发送警报。 (这将通过电子邮件进行,但为了方便起见,我刚刚包含了打印语句......这应该有效)

删除

while
功能,所有打印语句都会出现。

这是一个非常愚蠢的情况。即使

print("Can you see this message....")
print("Entering loop...")
也不会打印。这些
print
语句甚至不会在
while
循环中打印,因此即使
while
循环的执行存在问题(实际上不存在),它也应该打印。我会通过调试打印向您展示,但如果实际打印的内容像我告诉的那样,那么您就可以看到。

我的血压因此而严重升高。

compute_client
已通过身份验证,并且它返回正确的
vm_name
,那么为什么 - 每当我包含
while
循环时 - 它是否有嘶嘶声?

我对此非常生气。

import time, random, smtplib, inspect, string
from datetime import datetime
from email.mime.text import MIMEText
from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.compute 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()
python azure
1个回答
0
投票

如前所述,Azure Runbook 具有输出缓冲,这有时会阻止循环内立即显示打印语句。

    即使您将
  • flush=True

    添加到

    print
    ,循环也可能会连续运行,导致输出缓冲无法及时刷新。尝试添加额外的
    flush
    调用,或者考虑记录日志而不是使用
    print
    
    

  • 删除
  • while True

    循环并使用有限循环或限时循环进行测试,看看是否可以隔离问题。

    
    

打印也不是。代码已根据您的建议进行了更新,以便您可以看到我放置附加打印语句的位置。

脚本可能会在
到达

get_vm_status函数之前或在执行函数本身时阻塞。

首先在调用 
print

之前添加一个

get_vm_status

 语句来检查它是否被调用。然后,在 
get_vm_status
 函数中,在每个主要操作之前放置打印以跟踪其执行情况。
更新代码:

import time import random import smtplib import inspect import string from datetime import datetime from email.mime.text import MIMEText from azure.common.credentials import ServicePrincipalCredentials from azure.mgmt.compute 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()

如果 
"Before calling get_vm_status...."
    没有出现,则问题出在
  • compute_client
    service_principal_authentication()
     方法的初始化。
    如果 
    "Retrieving VM status......"
  • 未出现,则问题出在检索虚拟机状态的 API 调用中。
  • 如果 
    "Can you see this message?"
  • 未打印,则该函数可能未按预期返回或完成。
  •     
© www.soinside.com 2019 - 2024. All rights reserved.