no host下的Microsoft.Extensions.Logging使用

非宿主机环境下使用Microsoft.Extensions.Logging详解
本文介绍了如何在非宿主机环境中使用Microsoft.Extensions.Logging,强调在创建loggerFactory时必须使用using语句以确保日志完整输出。示例代码展示了不同日志级别的使用,并提到了过滤级别对日志输出的影响。

no host下的Microsoft.Extensions.Logging使用

用法如下,需要注意的是在非host情况下使用创建loggerFactory时必须要使用using语句。logger.log***是非阻塞语句,不使用using可能会导致程序在logger输出完成前退出,从而导致logger内容不全。

class Program{
    static void main(string[] args){
        using (var loggerFactory = LoggerFactory.Create(builder =>
            {
                builder.AddFilter("", level);
                builder.AddConsole();
            })) {
                
                var logger = loggerFactory.CreateLogger<Program>();
                logger.LogTrace("this is trace");
                logger.LogDebug("this is debug");
                logger.LogInformation("this is information");
                logger.LogWarning(logLevelWarning == "" ? "this is warning" : logLevelWarning);
                logger.LogError("this is error");
                logger.LogCritical("this is critical");
            }
    }
}

其它:

Microsoft.Extensions.Logging规定了七个输出级别,分别为Trace,Debug,Information,Warning,Error,Critical和None

过滤级别为trace时不过滤任何输出,过滤级别为None时无任何输出

要查看某一级别是否被过滤可调用logger.IsEnabled(LogLevel.Critical);查看,若为True则正常输出,若为False则无输出

System.InvalidOperationException:“No service for type 'TMRMagneticDetector.Services.LaserDistanceService' has been registered.” using System.Windows; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using TMRMagneticDetector.Services; using TMRMagneticDetector.ViewModels; using Application = System.Windows.Application; namespace TMRMagneticDetector { public partial class App : Application { public static IHost _host { get; private set; } public IServiceProvider ServiceProvider { get; private set; } public static ILoggerFactory? LoggerFactory { get; private set; } protected async void OnStartup(object sender, StartupEventArgs e) { //base.OnStartup(e); // 创建主机 _host = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder() .ConfigureServices(services => { ConfigureServices(services); }) .ConfigureLogging(logging => { logging.AddConsole(); logging.AddDebug(); logging.SetMinimumLevel(LogLevel.Information); }) .Build(); // Configure services var services = new ServiceCollection(); ConfigureServices(services); LoggerFactory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddConsole(); builder.SetMinimumLevel(LogLevel.Information); }); ServiceProvider = services.BuildServiceProvider(); // Create and show main window var mainWindow = ServiceProvider.GetRequiredService<MainWindow>(); mainWindow.Show(); // 启动主机 //await _host.StartAsync(); // 显示主窗口 //var mainWindow = _host.Services.GetRequiredService<MainWindow>(); //mainWindow.Show(); } private void ConfigureServices(IServiceCollection services) { // Logging services.AddLogging(builder => { builder.AddConsole(); builder.SetMinimumLevel(LogLevel.Information); }); // Services services.AddSingleton<ISerialPortService, SerialPortService>(provider => new SerialPortService( logger: provider.GetRequiredService<ILogger<SerialPortService>>() ) ); services.AddSingleton<DataProcessingService>(provider => new DataProcessingService( logger: provider.GetRequiredService<ILogger<DataProcessingService>>(), 0 ) ); services.AddSingleton<ILaserDistanceService, LaserDistanceService>(provider => new LaserDistanceService( logger: provider.GetRequiredService<ILogger<LaserDistanceService>>() ) ); services.AddSingleton<MagneticSourceLocationService>(provider => new MagneticSourceLocationService( ) ); services.AddSingleton<DetectionStateMachine>(provider => new DetectionStateMachine( logger: provider.GetRequiredService<ILogger<DetectionStateMachine>>(), provider.GetRequiredService<MagneticSourceLocationService>() ) ); services.AddSingleton<AlertService>(provider => new AlertService( logger: provider.GetRequiredService<ILogger<AlertService>>() ) ); services.AddSingleton<ReportGenerator>(provider => new ReportGenerator( logger: provider.GetRequiredService<ILogger<ReportGenerator>>() ) ); // ViewModels services.AddSingleton<MainViewModel>(provider => new MainViewModel( logger: provider.GetRequiredService<ILogger<MainViewModel>>(), provider.GetRequiredService<DetectionStateMachine>(), provider.GetRequiredService<LaserDistanceService>(), provider.GetRequiredService<AlertService>(), provider.GetRequiredService<ReportGenerator>(), provider.GetRequiredService<MagneticSourceLocationService>() ) ); // Windows services.AddTransient<MainWindow>(provider => new MainWindow( ) ); } } } /// <summary> /// 激光测距仪服务 /// </summary> public class LaserDistanceService : ILaserDistanceService, IDisposable { private readonly ILogger<LaserDistanceService> _logger; private SerialPort _serialPort; private CancellationTokenSource _cancellationTokenSource; private double _currentDistance = 1000.0; // 默认距离1000mm private double _triggerThreshold = 100.0; // mm private double _releaseThreshold = 50.0; // mm private bool _isDisposed; public event EventHandler<double> DistanceChanged; public event EventHandler<string> ErrorOccurred; public bool IsConnected => _serialPort?.IsOpen ?? false; public string PortName => _serialPort?.PortName ?? string.Empty; public LaserDistanceService(ILogger<LaserDistanceService> logger) { _logger = logger; }
11-13
.net8 .netcore dbug: Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler[4] Initializing Razor view compiler with no compiled views. dbug: Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory[12] Registered model binder providers, in the following order: Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BinderTypeModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ServicesModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.HeaderModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FloatingPointTypeModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.EnumTypeModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.DateTimeModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.SimpleTypeModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.TryParseModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.CancellationTokenModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ByteArrayModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FormFileModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FormCollectionModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.KeyValuePairModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.DictionaryModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ArrayModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.CollectionModelBinderProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexObjectModelBinderProvider info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[63] User profile is available. Using 'C:\Users\Administrator\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest. dbug: Microsoft.Extensions.Hosting.Internal.Host[1] Hosting starting dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] Reading data from file 'C:\Users\Administrator\AppData\Local\ASP.NET\DataProtection-Keys\key-3112a98c-0ea6-4bbd-b81a-7371dd2684ac.xml'. dbug: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[37] Reading data from file 'C:\Users\Administrator\AppData\Local\ASP.NET\DataProtection-Keys\key-7973feae-6c2e-433e-b462-385567895847.xml'. dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] Found key {3112a98c-0ea6-4bbd-b81a-7371dd2684ac}. dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[18] Found key {7973feae-6c2e-433e-b462-385567895847}. dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[13] Considering key {7973feae-6c2e-433e-b462-385567895847} with expiration date 2025-11-16 04:16:46Z as default key. dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] Forwarded activator type request from Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlDecryptor, Microsoft.AspNetCore.DataProtection, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlDecryptor, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 dbug: Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlDecryptor[51] Decrypting secret element using Windows DPAPI. dbug: Microsoft.AspNetCore.DataProtection.TypeForwardingActivator[0] Forwarded activator type request from Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60 dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.CngCbcAuthenticatedEncryptorFactory[4] Opening CNG algorithm 'AES' from provider '(null)' with chaining mode CBC. dbug: Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.CngCbcAuthenticatedEncryptorFactory[3] Opening CNG algorithm 'SHA256' from provider '(null)' with HMAC. dbug: Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider[2] Using key {7973feae-6c2e-433e-b462-385567895847} as the default key. dbug: Microsoft.AspNetCore.DataProtection.Internal.DataProtectionHostedService[65] Key ring with default key {7973feae-6c2e-433e-b462-385567895847} was loaded during application startup. dbug: Microsoft.AspNetCore.Watch.BrowserRefresh.BlazorWasmHotReloadMiddleware[0] Middleware loaded dbug: Microsoft.AspNetCore.Watch.BrowserRefresh.BrowserScriptMiddleware[0] Middleware loaded. Script /_framework/aspnetcore-browser-refresh.js (16493 B). dbug: Microsoft.AspNetCore.Watch.BrowserRefresh.BrowserScriptMiddleware[0] Middleware loaded. Script /_framework/blazor-hotreload.js (799 B). dbug: Microsoft.AspNetCore.Watch.BrowserRefresh.BrowserRefreshMiddleware[0] Middleware loaded: DOTNET_MODIFIABLE_ASSEMBLIES=debug, __ASPNETCORE_BROWSER_TOOLS=true info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:5080 dbug: Microsoft.AspNetCore.Hosting.Diagnostics[13] Loaded hosting startup assembly Site dbug: Microsoft.AspNetCore.Hosting.Diagnostics[13] Loaded hosting startup assembly Microsoft.WebTools.ApiEndpointDiscovery dbug: Microsoft.AspNetCore.Hosting.Diagnostics[13] Loaded hosting startup assembly Microsoft.AspNetCore.Watch.BrowserRefresh dbug: Microsoft.AspNetCore.Hosting.Diagnostics[13] Loaded hosting startup assembly Microsoft.WebTools.BrowserLink.Net info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Development info: Microsoft.Hosting.Lifetime[0] Content root path: C:\Users\Administrator\Desktop\BaseSiteLib\Site dbug: Microsoft.Extensions.Hosting.Internal.Host[2] Hosting started 运行时打印出这些是有什么问题吗
最新发布
11-15
import time import random import requests import json import logging import socket from pathlib import Path from openpyxl import load_workbook from selenium import webdriver from selenium.webdriver.edge.service import Service from selenium.webdriver.edge.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.action_chains import ActionChains from selenium.common.exceptions import TimeoutException, WebDriverException from fake_useragent import UserAgent, FakeUserAgentError # -------------------------- 新增:手动指定Edge浏览器和驱动路径 -------------------------- EDGE_BINARY_PATH = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" # 浏览器路径 EDGE_DRIVER_PATH = r"C:\Users\27570\Desktop\edgedriver_win32\msedgedriver.exe" # 驱动路径,需下载并指定 # ------------------------------------------------------------------------------------- # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("ip_query.log"), logging.StreamHandler() ] ) # -------------------------- 优化:整合网络连接检查 -------------------------- def check_internet_connection(): """检查网络连接是否正常,尝试多种连接方式提高可靠性""" try: # 尝试连接到Google的公共DNS服务器 socket.create_connection(("8.8.8.8", 53), timeout=5) logging.info("网络连接测试通过 (DNS)") return True except OSError: logging.warning("无法连接到DNS服务器,尝试HTTP请求...") try: # 尝试HTTP请求到百度 response = requests.get("https://www.baidu.com", timeout=5) if response.status_code == 200: logging.info("网络连接测试通过 (HTTP)") return True except requests.RequestException: logging.warning("HTTP请求失败,尝试HTTPS请求...") try: # 尝试HTTPS请求到百度 response = requests.get("https://www.baidu.com", timeout=5) if response.status_code == 200: logging.info("网络连接测试通过 (HTTPS)") return True except requests.RequestException: logging.error("HTTPS请求失败") return False # ------------------------------------------------------------------------------------- def build_query_url(base_url, ip_address, path_format="{ip}/", use_params=True, param_name="ip"): """构建IP查询URL,支持路径参数和查询参数两种格式""" if not base_url.startswith(('http://', 'https://')): base_url = 'https://' + base_url base_url = base_url.rstrip('/') try: if '.' in ip_address: # IPv4 socket.inet_pton(socket.AF_INET, ip_address) elif ':' in ip_address: # IPv6 socket.inet_pton(socket.AF_INET6, ip_address) else: raise ValueError("无效的IP地址") if ':' in ip_address: ip_address = f"[{ip_address}]" if use_params: # 使用查询参数的方式构造URL from urllib.parse import urlencode # 添加固定参数action=2 params = {param_name: ip_address, "action": 2} return f"{base_url}?{urlencode(params)}" else: # 原有的路径参数方式 from urllib.parse import quote encoded_ip = quote(ip_address) return f"{base_url}/{path_format.format(ip=encoded_ip)}" except socket.error: logging.error(f"无效的IP地址格式: {ip_address}") return None except Exception as e: logging.error(f"构建查询URL时出错: {str(e)}") return None # 手动配置的固定请求头 MANUAL_HEADERS = { 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'zh-CN,zh;q=0.9', 'cache-control': 'max-age=0', 'connection': 'keep-alive', 'cookie': '_c_WBKFRo=NWgPw1zeBaW3I2CtOcadfhJJw33TcEYmWMtyGzTE; Hm_lvt_f4f76646cd877e538aa1fbbdf351c548=1753560343,1753617545,1753793389,1753862286; HMACCOUNT=96B6BD9DE68EFF3B; PHPSESSID=o9fnnscr7sofru4b8r1khlde3f; Hm_lvt_f4f76646cd877e538aa1fbbdf351c548=1754123598; HMACCOUNT=96B6BD9DE68EFF3B; Hm_lpvt_f4f76646cd877e538aa1fbbdf351c548=1754611428; Hm_lpvt_f4f76646cd877e538aa1fbbdf351c548=1754613370', 'host': 'www.ip138.com', 'referer': 'https://www.ip138.com/iplookup.php?ip=27.154.214.154&action=2', 'sec-ch-ua': '"Not)A;Brand";v="8", "Chromium";v="138", "Microsoft Edge";v="138"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'document', 'sec-fetch-mode': 'navigate', 'sec-fetch-site': 'same-origin', 'sec-fetch-user': '?1', 'upgrade-insecure-requests': '1', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0' } def configure_driver(max_retries=5): """配置Edge浏览器驱动""" for attempt in range(max_retries): try: # 先检查网络连接 if not check_internet_connection(): raise Exception("网络连接不可用") # 创建Edge选项 edge_options = Options() # 1. 基础配置 edge_options.binary_location = EDGE_BINARY_PATH # 手动指定浏览器路径 edge_options.add_argument("--disable-blink-features=AutomationControlled") # 核心反检测 edge_options.add_experimental_option("excludeSwitches", ["enable-automation"]) edge_options.add_experimental_option("useAutomationExtension", False) edge_options.add_argument("--start-maximized") # 最大化窗口 # 2. 增强反检测 edge_options.add_argument("--disable-extensions") edge_options.add_argument("--disable-plugins-discovery") edge_options.add_argument("--disable-web-security") # 3. 随机化配置 features_to_disable = [ "AutomationControlled", "InterestCohort", "BlinkGenPropertyTrees" ] edge_options.add_argument(f"--disable-features={','.join(random.sample(features_to_disable, random.randint(2, 4)))}") screen_sizes = [(1366, 768), (1920, 1080), (1536, 864)] width, height = random.choice(screen_sizes) edge_options.add_argument(f"--window-size={width},{height}") if random.random() > 0.5: edge_options.add_argument("--disable-gpu") else: edge_options.add_argument("--enable-gpu-rasterization") # 4. 资源加载控制 prefs = { "profile.managed_default_content_settings.images": 2, "profile.managed_default_content_settings.stylesheets": 2, } edge_options.add_experimental_option("prefs", prefs) edge_options.page_load_strategy = 'eager' # 只等待DOM加载 # 5. 使用手动指定的驱动路径 try: service = Service(EDGE_DRIVER_PATH) # 手动指定驱动路径 logging.info(f"使用手动指定的驱动路径: {EDGE_DRIVER_PATH}") except Exception as e: logging.error(f"驱动路径配置错误: {str(e)}") raise # 6. 创建浏览器实例 driver = webdriver.Edge(service=service, options=edge_options) # 7. 隐藏自动化特征 driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", { "source": """ // 核心:隐藏webdriver标志 Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); // 模拟Chrome特征 window.chrome = { runtime: {} }; // 模拟时区 Intl.DateTimeFormat().resolvedOptions().timeZone = ['Asia/Shanghai', 'Asia/Beijing'][Math.floor(Math.random() * 2)]; """ }) # 8. 设置超时 driver.set_page_load_timeout(30) driver.set_script_timeout(30) # 9. 应用手动配置的请求头 logging.info(f"应用手动配置的请求头: {json.dumps(MANUAL_HEADERS, indent=2)[:100]}...") driver.execute_cdp_cmd("Network.setUserAgentOverride", { "userAgent": MANUAL_HEADERS["user-agent"], "accept": MANUAL_HEADERS["accept"], "acceptLanguage": MANUAL_HEADERS["accept-language"], }) logging.info(f"浏览器驱动初始化成功 (尝试 {attempt+1}/{max_retries})") return driver except Exception as e: logging.error(f"配置浏览器驱动失败 (尝试 {attempt+1}/{max_retries}): {str(e)}") if attempt < max_retries - 1: wait_time = 2 ** attempt + random.uniform(5, 10) logging.info(f"将在 {wait_time:.2f} 秒后重试") time.sleep(wait_time) logging.critical("达到最大重试次数,无法初始化浏览器驱动") return None def change_user_agent(driver): """更换为手动配置的请求头""" logging.info(f"应用手动配置的请求头: {json.dumps(MANUAL_HEADERS, indent=2)[:100]}...") driver.execute_cdp_cmd("Network.setUserAgentOverride", { "userAgent": MANUAL_HEADERS["user-agent"], "accept": MANUAL_HEADERS["accept"], "acceptLanguage": MANUAL_HEADERS["accept-language"], }) driver.refresh() time.sleep(random.uniform(2, 4)) def handle_cookies(driver): """处理和保存Cookie""" cookies = driver.get_cookies() logging.info(f"获取到 {len(cookies)} 个Cookie") return cookies def is_banned(driver): """检测是否被封禁""" try: banned_xpaths = [ '//div[contains(text(), "访问被阻止")]', '//div[contains(text(), "验证码")]', '//div[contains(text(), "您的IP已被封禁")]', ] for xpath in banned_xpaths: if WebDriverWait(driver, 5).until( EC.presence_of_element_located((By.XPATH, xpath)) ): logging.warning("检测到封禁页面") return True return False except: return False def check_dynamic_element(driver, xpaths): """检查网页上是否存在任一动态XPath的元素""" for i, xpath in enumerate(xpaths, 1): try: WebDriverWait(driver, 5).until( EC.presence_of_element_located((By.XPATH, xpath)) ) logging.info(f"使用动态元素XPath {i}: {xpath}") return True except: continue return False def get_result_element(driver, xpaths): """尝试获取任一结果元素""" for i, xpath in enumerate(xpaths, 1): try: element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, xpath)) ) logging.info(f"使用结果元素XPath {i}: {xpath}") return element except: continue return None def simulate_human_behavior(driver): """模拟人类浏览行为""" try: # 随机滚动页面 scroll_height = driver.execute_script("return document.body.scrollHeight") scroll_steps = random.randint(3, 7) for i in range(scroll_steps): scroll_to = int(scroll_height * (i + 1) / scroll_steps) driver.execute_script(f"window.scrollTo(0, {scroll_to})") time.sleep(random.uniform(0.5, 1.5)) # 随机移动鼠标 actions = ActionChains(driver) elements = driver.find_elements(By.TAG_NAME, "a") if elements: for _ in range(random.randint(1, 3)): element = random.choice(elements) actions.move_to_element(element).perform() time.sleep(random.uniform(0.3, 0.8)) except Exception as e: logging.warning(f"模拟人类行为时出错: {e}") def query_ip(driver, ip_address, base_url, xpath_expressions, dynamic_xpaths, max_retries=5): """查询IP信息,添加封禁检测和处理""" if not ip_address or not isinstance(ip_address, str) or ip_address.strip() == "": logging.warning(f"无效的IP地址: {ip_address}") return "无效IP" ip_address = ip_address.strip() for attempt in range(max_retries): try: if attempt > 0: wait_time = 2 ** attempt + random.uniform(3, 7) logging.info(f"第 {attempt+1} 次重试前等待 {wait_time:.2f} 秒...") time.sleep(wait_time) change_user_agent(driver) query_url = build_query_url(base_url, ip_address) if not query_url: logging.error(f"无法构建有效的查询URL,IP: {ip_address}") return "无效URL" logging.info(f"访问查询URL (尝试 {attempt+1}/{max_retries}): {query_url}") try: driver.get(query_url) time.sleep(random.uniform(8, 15)) if is_banned(driver): logging.warning(f"IP {ip_address} 查询时被封禁") driver.quit() time.sleep(5) driver = configure_driver() time.sleep(5) continue current_url = driver.current_url if current_url == "data:," or "about:blank" in current_url: raise Exception("浏览器加载了空白页面") simulate_human_behavior(driver) time.sleep(random.uniform(2, 5)) handle_cookies(driver) except TimeoutException: logging.warning(f"页面加载超时,尝试重新加载") driver.refresh() time.sleep(15) continue if check_dynamic_element(driver, dynamic_xpaths): logging.info(f"检测到动态元素,结果将设为'动态'") return "动态" result_element = get_result_element(driver, xpath_expressions) if result_element: return result_element.text.strip() else: raise Exception("无法找到结果元素") except WebDriverException as e: logging.error(f"WebDriver错误 (尝试 {attempt+1}/{max_retries}): {str(e)}") if "ERR_EMPTY_RESPONSE" in str(e) or "ERR_CONNECTION_RESET" in str(e): logging.warning("检测到连接错误,尝试重启浏览器...") driver.quit() time.sleep(15) driver = configure_driver() time.sleep(10) else: time.sleep(2 ** attempt + random.uniform(5, 10)) continue except Exception as e: logging.error(f"查询IP {ip_address} 失败 (尝试 {attempt+1}/{max_retries}): {str(e)}") time.sleep(2 ** attempt + random.uniform(5, 10)) continue logging.error(f"IP {ip_address} 查询失败,已达到最大重试次数") driver.save_screenshot(f"error_{ip_address}.png") return "查询失败" def is_row_hidden(worksheet, row_idx): """检查Excel行是否被隐藏""" return worksheet.row_dimensions[row_idx].hidden def process_excel(input_file, base_url, xpath_expressions, dynamic_xpaths, ip_column='A', result_column='I', start_row=2): """处理Excel文件""" wb = load_workbook(input_file) ws = wb.active has_filter = ws.auto_filter.ref is not None logging.info(f"检测到筛选: {has_filter}") driver = configure_driver() if not driver: logging.critical("无法初始化浏览器驱动,退出程序") return visible_rows = [] for row_idx in range(start_row, ws.max_row + 1): row_dim = ws.row_dimensions.get(row_idx) if not row_dim or not row_dim.hidden: visible_rows.append(row_idx) logging.info(f"可见行共{len(visible_rows)}行") total_visible = len(visible_rows) processed_count = 0 try: for i, row in enumerate(visible_rows, 1): ip_address = ws[f"{ip_column}{row}"].value if not ip_address: logging.info(f"第 {row} 行IP地址为空,跳过") continue logging.info(f"正在查询IP: {ip_address} ({i}/{total_visible})") result = query_ip(driver, ip_address, base_url, xpath_expressions, dynamic_xpaths) ws[f"{result_column}{row}"] = result processed_count += 1 if i % 3 == 0 or i == total_visible: wb.save(input_file) logging.info(f"已保存进度: {i}/{total_visible} 到 {input_file}") wait_time = random.uniform(20,40) logging.info(f"等待 {wait_time:.2f} 秒后继续...") time.sleep(wait_time) if i % 10 == 0: extra_wait = random.uniform(40,60) logging.info(f"已处理 {i} 个IP,额外休息 {extra_wait:.2f} 秒...") time.sleep(extra_wait) if i % 20 == 0: logging.info(f"已处理 {i} 个IP,重启浏览器以避免被检测...") driver.quit() time.sleep(15) driver = configure_driver() if not driver: logging.critical("无法重新初始化浏览器驱动,退出程序") return except Exception as e: logging.critical(f"处理过程中发生意外错误: {str(e)}") finally: if driver: driver.quit() wb.save(input_file) logging.info(f"已保存最终结果到 {input_file}") logging.info(f"处理完成!共处理 {processed_count}/{total_visible} 个可见IP地址") if __name__ == "__main__": INPUT_FILE = r"C:\Users\27570\Desktop\飞塔-福建-简版-更新版20250730.xlsx" # 修改为新的基础URL BASE_URL = "https://www.ip138.com/iplookup.php" # 配置两种XPath表达式 XPATH_EXPRESSIONS = [ '/html/body/div/div[2]/div[1]/div/table/tbody/tr[2]/td[2]', '/html/body/div/div[2]/div[2]/div/div[2]/div[1]/div/div[2]/div[2]/div[2]/table/tbody/tr[2]/td[2]' ] DYNAMIC_XPATHS = [ '/html/body/div/div[2]/div[1]/div/p/a', '/html/body/div/div[2]/div[2]/div/div[2]/div[1]/div/div[2]/div[2]/div[1]/p[1]/a' ] max_main_retries = 3 for main_attempt in range(max_main_retries): try: logging.info(f"开始处理Excel文件 (尝试 {main_attempt+1}/{max_main_retries})") process_excel(INPUT_FILE, BASE_URL, XPATH_EXPRESSIONS, DYNAMIC_XPATHS) break except Exception as e: logging.critical(f"主程序执行失败 (尝试 {main_attempt+1}/{max_main_retries}): {str(e)}") if main_attempt < max_main_retries - 1: wait_time = 10 + random.uniform(10, 30) logging.info(f"将在 {wait_time:.2f} 秒后重试") time.sleep(wait_time) else: logging.critical("达到最大重试次数,程序终止") 以上代码在运行时出现了以下问题,解决问题并给我完整代码 Message: session not created: probably user data directory is already in use, please specify a unique value for --user-data-dir argument, or don't use --user-data-dir; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#sessionnotcreatedexception Stacktrace: GetHandleVerifier [0x0xf6d593+37219] (No symbol) [0x0xe1a716] (No symbol) [0x0xbe51ce] (No symbol) [0x0xc0d881] (No symbol) [0x0xc08a43] (No symbol) [0x0xc3d78b] (No symbol) [0x0xc3d22a] (No symbol) [0x0xc324f6] (No symbol) [0x0xc13327] (No symbol) [0x0xc12723] (No symbol) [0x0xc13144] sqlite3_dbdata_init [0x0x105a89c+518364] sqlite3_dbdata_init [0x0x1141ab0+1465072] sqlite3_dbdata_init [0x0x11413e5+1463333] sqlite3_dbdata_init [0x0x11328ec+1403180] sqlite3_dbdata_init [0x0x11422d2+1467154] (No symbol) [0x0xe31d9d] (No symbol) [0x0xe25108] (No symbol) [0x0xe252fb] (No symbol) [0x0xe0a649] BaseThreadInitThunk [0x0x75525d49+25] RtlInitializeExceptionChain [0x0x7706d1ab+107] RtlGetAppContainerNamedObjectPath [0x0x7706d131+561]
08-09
<think>我们正在讨论Microsoft.Extensions.Logging使用指南和常见问题。根据引用内容,我们可以整合以下信息:1.引用[1]和[4]提到了Karambolo.Extensions.Logging.File,这是一个文件日志记录提供程序,支持结构化日志(JSON格式)。2.引用[2]提到了Microsoft.Extensions.Logging.Log4Net.AspNetCore,这是一个将Log4net集成到Microsoft.Extensions.Logging的库。3.引用[3]和[5]展示了在Startup或Program中配置日志的基本方法。因此,我们将围绕Microsoft.Extensions.Logging(MEL)展开,包括基本配置、与第三方日志框架的集成、文件日志记录等。###Microsoft.Extensions.Logging使用指南####1.**基本配置**在ASP.NETCore中,MEL是内置的日志系统。配置通常在`Program.cs`或`Startup.cs`中完成。```csharpvarbuilder=WebApplication.CreateBuilder(args);//添加日志配置builder.Logging.ClearProviders();//清除默认的日志提供程序builder.Logging.AddConsole();//添加控制台日志builder.Logging.AddDebug();//添加调试日志//设置默认日志级别builder.Logging.SetMinimumLevel(LogLevel.Information);//按命名空间设置日志级别builder.Logging.AddFilter("Microsoft",LogLevel.Warning);builder.Logging.AddFilter("System",LogLevel.Warning);builder.Logging.AddFilter("MyApp",LogLevel.Debug);```####2.**使用文件日志**通过引用[1][4][5]提到的Karambolo.Extensions.Logging.File,我们可以将日志输出到文件。**步骤1**:安装NuGet包```Install-PackageKarambolo.Extensions.Logging.File```**步骤2**:配置```csharpbuilder.Logging.AddFile(configuration=>{configuration.RootPath=AppContext.BaseDirectory;configuration.Files=new[]{newLogFileOptions{Path="logs/app.log",MinLevel=LogLevel.Information}};});```或者通过`appsettings.json`配置:```json{"Logging":{"File":{"Path":"logs/app.log","MinLevel":"Information"}}}```然后在代码中调用:```csharpbuilder.Logging.AddFile();//自动读取配置```####3.**集成Log4net**根据引用[2],我们可以使用`Microsoft.Extensions.Logging.Log4Net.AspNetCore`集成Log4net。**步骤1**:安装NuGet包```Install-PackageMicrosoft.Extensions.Logging.Log4Net.AspNetCore```**步骤2**:添加log4net.config配置文件```xml<?xmlversion="1.0"encoding="utf-8"?><log4net><appendername="file"type="log4net.Appender.RollingFileAppender"><filevalue="logs/log4net.log"/><layouttype="log4net.Layout.PatternLayout"><conversionPatternvalue="%date[%thread]%level%logger-%message%newline"/></layout></appender><root><levelvalue="INFO"/><appender-refref="file"/></root></log4net>```**步骤3**:在代码中配置```csharpbuilder.Logging.AddLog4Net();```####4.**结构化日志**使用Karambolo.Extensions.Logging.File.Json包可以输出JSON格式的结构化日志。```csharpbuilder.Logging.AddJsonFile();//使用默认配置```####5.**依赖注入中使用日志**在控制器或服务中注入`ILogger<T>`:```csharppublicclassHomeController:Controller{privatereadonlyILogger<HomeController>_logger;publicHomeController(ILogger<HomeController>logger){_logger=logger;}publicIActionResultIndex(){_logger.LogInformation("访问首页");_logger.LogError("模拟错误");returnView();}}```###常见问题解决####**Q1:如何动态更改日志级别?**A1:使用配置系统(如`appsettings.json`)并配合重载配置。在运行时修改配置后,调用`IConfiguration.Reload()`,但注意大多数日志提供程序不支持热更新。对于Log4net,可以通过`XmlConfigurator.Configure`重新加载配置。####**Q2:如何将日志输出到多个目标?**A2:同时添加多个日志提供程序(如控制台、文件、Log4net等),每个提供程序可以单独配置级别和过滤。####**Q3:如何记录结构化日志?**A3:使用支持结构化的日志提供程序(如Serilog、Karambolo.Extensions.Logging.File.Json)。在日志消息中使用命名占位符:```csharp_logger.LogInformation("用户{UserId}登录失败,尝试次数{AttemptCount}",userId,count);```####**Q4:如何集成第三方日志框架?**A4:通过相应的适配器包(如`Microsoft.Extensions.Logging.Log4Net.AspNetCore`、`Serilog.Extensions.Logging`)将MEL桥接到第三方框架。####**Q5:日志文件如何按日期滚动?**A5:在Karambolo.Extensions.Logging.File中,配置`FileOptions`的`MaxFileSize`和`MaxFiles`等属性。在Log4net中,使用`RollingFileAppender`并设置滚动策略。###最佳实践1.**避免过度日志记录**:设置合理的日志级别,避免生产环境输出过多日志。2.**使用作用域**:在事务处理中使用日志作用域:```csharpusing(_logger.BeginScope("事务ID:{TransactionId}",Guid.NewGuid())){//日志会自动附加作用域信息}```3.**异常日志**:始终使用`LogError`或`LogCritical`记录异常,并传递异常对象:```csharptry{...}catch(Exceptionex){_logger.LogError(ex,"操作失败");}```§§相关问题§§1.如何在运行时动态更改Microsoft.Extensions.Logging的日志级别?2.Microsoft.Extensions.Logging如何与Serilog集成?3.如何将Microsoft.Extensions.Logging的日志输出到Elasticsearch?</think>### Microsoft.Extensions.Logging 使用指南与常见问题解决方案 #### 一、基础配置与使用 Microsoft.Extensions.Logging (MEL) 是.NET Core的官方日志抽象框架,支持多提供程序扩展。 **1. 基本配置(.NET 6+)** ```csharp var builder = WebApplication.CreateBuilder(args); // 添加控制台和调试日志 builder.Logging.AddConsole(); builder.Logging.AddDebug(); // 设置全局日志级别 builder.Logging.SetMinimumLevel(LogLevel.Information); // 按命名空间过滤日志 builder.Logging.AddFilter("Microsoft", LogLevel.Warning); builder.Logging.AddFilter("MyApp", LogLevel.Debug); ``` **2. 结构化日志输出** ```csharp // 在控制器/服务中使用 public class MyService(ILogger<MyService> logger) { public void ProcessOrder(Order order) { logger.LogInformation("处理订单 {OrderId}, 金额: ${Amount}", order.Id, order.Total); // 结构化参数[^1] try { /* 业务逻辑 */ } catch (Exception ex) { logger.LogError(ex, "订单处理失败: {OrderId}", order.Id); } } } ``` #### 二、文件日志集成 使用 **Karambolo.Extensions.Logging.File** 实现高效文件日志: **1. 安装与配置** ```bash dotnet add package Karambolo.Extensions.Logging.File dotnet add package Karambolo.Extensions.Logging.File.Json # JSON格式 ``` **2. 基础配置** ```csharp builder.Logging.AddFile(configuration => { configuration.RootPath = AppContext.BaseDirectory; configuration.Files = new[] { new LogFileOptions { Path = "logs/app.log", MinLevel = LogLevel.Information } }; }); ``` **3. JSON结构化日志** ```csharp builder.Logging.AddJsonFile(options => { options.File = new LogFileOptions { Path = "logs/structured.json" }; options.JsonSerializerOptions = new() { WriteIndented = true }; }); ``` 生成日志示例: ```json { "Timestamp": "2023-10-05T12:34:56Z", "Level": "Information", "Message": "处理订单 12345, 金额: $99.99", "Properties": { "OrderId": 12345, "Amount": 99.99 } } ``` #### 三、Log4net集成 使用 **Microsoft.Extensions.Logging.Log4Net.AspNetCore** 桥接Log4net: **1. 安装与配置** ```bash dotnet add package Microsoft.Extensions.Logging.Log4Net.AspNetCore ``` **2. 配置log4net.config** ```xml <log4net> <appender name="RollingFile" type="log4net.Appender.RollingFileAppender"> <file value="logs/log4net.log" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %level %logger - %message%newline" /> </layout> </appender> <root> <level value="INFO" /> <appender-ref ref="RollingFile" /> </root> </log4net> ``` **3. 代码集成** ```csharp builder.Logging.AddLog4Net(); // 自动加载log4net.config ``` #### 四、高级场景与最佳实践 **1. 日志作用域(关联操作)** ```csharp using (logger.BeginScope("事务ID:{TransactionId}", Guid.NewGuid())) { logger.LogInformation("开始处理"); // 相关日志自动附加事务ID } ``` **2. 动态日志级别切换** ```csharp // 在运行时更新日志级别 var loggerFactory = app.Services.GetRequiredService<ILoggerFactory>(); var filterOptions = app.Services.GetRequiredService<IOptionsMonitor<LoggerFilterOptions>>(); filterOptions.CurrentValue.MinLevel = LogLevel.Debug; // 动态调整 ``` **3. 性能优化** - 使用编译时日志源生成(.NET 6+): ```csharp [LoggerMessage(EventId = 100, Level = LogLevel.Error, Message = "订单 {OrderId} 处理失败")] public static partial void LogOrderError(this ILogger logger, int orderId); ``` #### 五、常见问题解决方案 **Q1: 日志文件不生成?** - 检查文件路径权限 - 确认配置中`RootPath`有效性 - 验证日志级别是否匹配 **Q2: 如何集成到EF Core?** ```csharp // 在DbContext配置中启用日志 optionsBuilder.UseSqlServer(connectionString) .LogTo(Console.WriteLine, LogLevel.Information); // 输出到控制台 ``` **Q3: 如何实现日志分割?** 在Karambolo配置中: ```csharp new LogFileOptions { Path = "logs/app-{Date:yyyyMMdd}.log", // 按日期分割 MaxFileSize = 10 * 1024 * 1024, // 10MB分割 MaxFiles = 30 // 保留30天 } ``` **Q4: 如何与Application Insights集成?** ```csharp builder.Logging.AddApplicationInsights( configureTelemetryConfiguration: config => config.ConnectionString = "YOUR_CONNECTION_STRING", configureApplicationInsightsLoggerOptions: _ => {} ); ``` #### 六、最佳实践 1. **结构化日志优先**:始终使用命名占位符而非字符串拼接[^1] 2. **错误日志规范**:始终记录完整异常对象 ```csharp // 错误做法 logger.LogError($"错误: {ex.Message}"); // 正确做法 logger.LogError(ex, "处理失败"); ``` 3. **生产环境配置**: ```json "Logging": { "File": { "MinLevel": "Warning", "MaxFiles": 7 } } ``` > **调试提示**:开发环境使用`appsettings.Development.json`配置详细日志,生产环境通过环境变量覆盖敏感设置[^3][^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值