পাইথন লগিং মডিউলটি ব্যবহার করার সময় সদৃশ লগ আউটপুট


105

আমি পাইথন লগার ব্যবহার করছি। নিম্নলিখিতটি আমার কোড:

import os
import time
import datetime
import logging
class Logger :
   def myLogger(self):
      logger = logging.getLogger('ProvisioningPython')
      logger.setLevel(logging.DEBUG)
      now = datetime.datetime.now()
      handler=logging.FileHandler('/root/credentials/Logs/ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log')
      formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
      handler.setFormatter(formatter)
      logger.addHandler(handler)
      return logger

আমার সমস্যাটি হ'ল আমি প্রতিটি logger.infoকলের জন্য লগ ফাইলে একাধিক এন্ট্রি পাই । আমি কীভাবে এটি সমাধান করতে পারি?


আমার জন্য কাজ কর. পাইথন ৩.২ এবং উইন্ডোজ এক্সপি।
জুলজিন

2
আপনি কি একাধিক লগার দৃষ্টান্ত তৈরি করেন নি?
গান্ডি

হ্যাঁ. বিভিন্ন ফাইলগুলিতে আমি জাভা প্রকল্পগুলির মতো নতুন উদাহরণ নিচ্ছি। এটি সমস্যা তৈরি করছে কিনা তা দয়া করে আমাকে উল্লেখ করুন।
ব্যবহারকারী 865438

উত্তর:


94

logging.getLogger()ইতিমধ্যে একটি Singleton হয়। ( ডকুমেন্টেশন )

সমস্যাটি হ'ল প্রতিবার আপনি কল করার সময় myLogger()এটি অন্য হ্যান্ডলারটি যুক্ত করে যা ডুপ্লিকেট লগগুলির কারণ হয়।

সম্ভবত এরকম কিছু?

import os
import time
import datetime
import logging

loggers = {}

def myLogger(name):
    global loggers

    if loggers.get(name):
        return loggers.get(name)
    else:
        logger = logging.getLogger(name)
        logger.setLevel(logging.DEBUG)
        now = datetime.datetime.now()
        handler = logging.FileHandler(
            '/root/credentials/Logs/ProvisioningPython' 
            + now.strftime("%Y-%m-%d") 
            + '.log')
        formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        loggers[name] = logger

        return logger

3
আমি মনে করি এর পরিবর্তে আপনার লগার থাকতে হবে upআপডেট (ডিক ((নাম, লগার)))।
অ্যাক্রোফোবিয়া

কেন loggers.update(dict(name=logger))? সহজ না loggers[name] = logger?
রায়ান জে ম্যাককাল

@ রায়ানজেএমসিকেল সেই সময়টি আমি ব্যবহৃত কোডিং কনভেনশন ছিল। কোডটি এখন যেমনটি পর্যালোচনা করার পরে, আমি দেখতে পেয়েছি এটি ভেঙে গেছে। loggers.update(dict(name=logger))একটি সিঙ্গল কী বলে একটি অভিধান তৈরি করবে nameএবং অবিচ্ছিন্নভাবে একই কীটি আপডেট করবে। আমি আশ্চর্য হয়েছি যে এই কোডটি বেশ ভেঙে যাওয়ার আগে কেউ এর আগে উল্লেখ করেনি :) প্রয়োজনীয় সংশোধন করবে।
ওয়ার্নার স্মিত

আমি দেখতে পাচ্ছি @ অ্যাক্রোফোবিয়া এই যুগে যুগে চলে আসছিল। ধন্যবাদ।
ওয়ার্নার স্মিত

গ্লোবাল loggersডিকশনারিটি রিডানড্যান্টের সাথে নয় logging.getLogger? যেহেতু আপনি সত্যিই কেবল অতিরিক্ত হ্যান্ডলার যুক্ত করা এড়াতে চান তাই মনে হচ্ছে আপনি নীচের উত্তরগুলি হ্যান্ডলারের জন্য সরাসরি চেক করতে চান
এম্বেওয়ে

60

পাইথন ৩.২ যেহেতু হ্যান্ডলারগুলি ইতিমধ্যে উপস্থিত রয়েছে কিনা তা আপনি কেবল পরীক্ষা করতে পারেন এবং যদি তাই হয় তবে নতুন হ্যান্ডলার যুক্ত করার আগে এগুলি সাফ করুন। ডিবাগ করার সময় এটি বেশ সুবিধাজনক এবং কোডটিতে আপনার লগার সূচনা অন্তর্ভুক্ত রয়েছে

if (logger.hasHandlers()):
    logger.handlers.clear()

logger.addHandler(handler)

ভাল উত্তর, থেক্স :))
গ্যাভরিল কোহেন

2
নোট করুন যে হ্যাশ হ্যান্ডলারগুলি () পাইস্টেস্টে সত্য ফিরে আসবে যেখানে কোনও হ্যান্ডলারটি রুট লগারে যুক্ত করা হয়েছে, এমনকি আপনার স্থানীয় / কাস্টম হ্যান্ডলারগুলি এখনও যোগ করা হয়নি। এই ক্ষেত্রে লেন (লগার.হ্যান্ডলারগুলি) (গিলিয়ামের উত্তর অনুসারে) 0 ফিরে আসবে, সুতরাং এটি আরও ভাল বিকল্প হতে পারে।
অনুদান

এটি আমি যা খুঁজছিলাম তার আসল সমাধান।
এক্সক্যানজি

45
import datetime
import logging
class Logger :
    def myLogger(self):
       logger=logging.getLogger('ProvisioningPython')
       if not len(logger.handlers):
          logger.setLevel(logging.DEBUG)
          now = datetime.datetime.now()
          handler=logging.FileHandler('/root/credentials/Logs/ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log')
          formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
          handler.setFormatter(formatter)
          logger.addHandler(handler)
        return logger

আমার জন্য কৌশল তৈরি

পাইথন ২.7 ব্যবহার করে


1
মডিউলটি পুনরায় লোড করার পরেও এটি কাজ করে (অন্য উত্তরগুলির ক্ষেত্রে এটি নয়)
yco

3
টিপটির জন্য ধন্যবাদ, বিটিডব্লিউ একটি তালিকা ফাঁকা আছে কিনা তা যাচাই করার জন্য আপনাকে "লেন" অপারেটরটি ব্যবহারের দরকার নেই যা আপনি সরাসরি আমার_ তালিকাতে ব্যবহার করতে পারেন: ..
rkachach

26

আমি ইতিমধ্যে সিঙ্গলটনlogger হিসাবে ব্যবহার করেছি এবং চেক করেছি , তবে এখনও নকল পেয়েছি : এটি ফর্ম্যাট আউটপুট ছিল, তারপরে অপরঠিত।if not len(logger.handlers)

আমার ক্ষেত্রে সমাধান : logger.propagate = False

এই উত্তর এবং দস্তাবেজ ক্রেডিট ।


1
আমি বুঝতে পেরেছি যে দ্বিগুণ লগিং রুটলগার এবং আমার স্ট্রিমহ্যান্ডলার থেকে হয়েছিল, তবে এটি না করা পর্যন্ত সমস্যাটি (স্ট্রিমহ্যান্ডলারটিতে আমার ফর্ম্যাটরটি রাখার সময়) সমাধান করতে পারিনি।
Xender YzWich

10

আপনি Logger.myLogger()একাধিকবার কল করছেন । এটির উদাহরণস্বরূপ এটা কোথাও ফেরৎ সঞ্চয় করুন এবং পুনরায় ব্যবহার করে

এছাড়াও পরামর্শ দিন যে কোনও হ্যান্ডলার যুক্ত হওয়ার আগে আপনি লগইন করলে একটি ডিফল্ট StreamHandler(sys.stderr)তৈরি হবে।


বাস্তবে আমি জাভাতে ব্যবহার করার সাথে সাথে লগার দৃষ্টান্তটি অ্যাক্সেস করার চেষ্টা করছি it's তবে এটি পুরো প্রকল্পের জন্য একবার তৈরি করার দরকার আছে কিনা তা আমি জানি না।
ব্যবহারকারী 865438

1
@ ব্যবহারকারী 865483: মাত্র একবার। সমস্ত স্ট্যান্ডার্ড লাইব্রেরির লগারগুলি সিলেটলেট।
ম্যাট জয়েনার

5

এটি @ rm957377 এর উত্তরের একটি সংযোজন তবে এটি কেন ঘটছে তার একটি ব্যাখ্যা সহ । আপনি যখন এডাব্লুএসে ল্যাম্বডা ফাংশনটি চালান, তখন তারা আপনার ফাংশনটিকে মোড়ানো উদাহরণের মধ্যে থেকে কল করে যা একাধিক কলের জন্য জীবিত থাকে। অর্থ, আপনি যদি addHandler()আপনার ফাংশনের কোডের মধ্যে কল করেন তবে এটি প্রতিবার ফাংশনটি চালানোর সময় লগিং সিঙ্গলটনে সদৃশ হ্যান্ডলার যুক্ত করতে থাকবে। লগিং সিঙ্গলটন আপনার লাম্বদা ফাংশনের একাধিক কলের মাধ্যমে অব্যাহত রয়েছে।

এটি সমাধানের জন্য আপনি আপনার হ্যান্ডলারগুলি সেগুলির মাধ্যমে সেট করার আগে সাফ করতে পারেন:

logging.getLogger().handlers.clear()
logging.getLogger().addHandler(...)

কোনওভাবে আমার ক্ষেত্রে লগার হ্যান্ডলাররা .info()কলটিতে ইভেন্টে যোগ হয় যা আমি বুঝতে পারি না।
ইভজেনি

4

আপনার লগার একক হিসাবে কাজ করা উচিত। আপনার এটি একবারের বেশি তৈরি করা উচিত নয়। এটি দেখতে কেমন হতে পারে তার উদাহরণ এখানে দেওয়া হয়েছে:

import os
import time
import datetime
import logging
class Logger :
    logger = None
    def myLogger(self):
        if None == self.logger:
            self.logger=logging.getLogger('ProvisioningPython')
            self.logger.setLevel(logging.DEBUG)
            now = datetime.datetime.now()
            handler=logging.FileHandler('ProvisioningPython'+ now.strftime("%Y-%m-%d") +'.log')
            formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
            handler.setFormatter(formatter)
            self.logger.addHandler(handler)
        return self.logger

s = Logger()
m = s.myLogger()
m2 = s.myLogger()
m.info("Info1")
m2.info("info2")

তারপর আবার যদি আমি বিভিন্ন ফাইলে বিভিন্ন উদাহরণ নিতে যাচ্ছি। ধরা যাক ফাইল 1 এস = লগার () মি = এস.মিলোগার () এবং ফাইল 2 এস = লগারে () এটি m2 = s.myLogger () কাজ করবে বা করবে না
ব্যবহারকারী 865438

তবুও আমি বহুবার একই লগের অনুলিপি পাচ্ছি। থ্রেডের ভিতরে থাকা লগগুলি একের বেশি প্রিন্ট করে কিনা তা আমার সন্দেহ আছে lease দয়া করে আমাকে এতে সহায়তা করুন।
ব্যবহারকারী 865438

1
@ ব্যবহারকারী 865438, বাস্তবায়নটিকে এককভাবে তৈরি করার বিষয়ে আমাদের উদ্বিগ্ন হওয়ার দরকার নেই (এটি ইতিমধ্যে রয়েছে)। সাব-মডিউলগুলিতে লগ করার জন্য, সরকারী লগিং কুকবুক লিঙ্কটি অনুসরণ করুন । মূলত লগারদের নামকরণের সময় আপনাকে নামকরণের স্তরক্রম অনুসরণ করতে হবে এবং এটি বাকীগুলির যত্ন নেয়।
নারায়ণ

4

লগার প্রয়োগ ইতিমধ্যে একটি সিঙ্গলটন।

লগিংয়ের জন্য একাধিক কল getgetLogger ('someLogger') একই লগার অবজেক্টের একটি রেফারেন্স দেয়। এটি একই মডিউলের মধ্যেই নয়, একই সময় পাইথন ইন্টারপ্রেটার প্রক্রিয়াধীন মডিউলগুলিতেও এটি সত্য। একই বস্তুর রেফারেন্সের জন্য এটি সত্য; তদুপরি, অ্যাপ্লিকেশন কোডটি একটি মডিউলে পিতা-মাতার লগারকে সংজ্ঞায়িত করতে ও কনফিগার করতে পারে এবং একটি পৃথক মডিউলে একটি শিশু লগার তৈরি করতে পারে (তবে কনফিগার করে না) এবং সন্তানের কাছে সমস্ত লগার কল পিতামাতার কাছে পৌঁছে যাবে। এখানে একটি প্রধান মডিউল

উত্স- একাধিক মডিউল লগিং ব্যবহার করে

সুতরাং আপনার যেভাবে এটি ব্যবহার করা উচিত তা হ'ল -

ধরা যাক আমরা মূল মডিউলে 'মেইন_লগার' নামে একটি লগার তৈরি এবং কনফিগার করেছি (যা কেবল লগারকে কনফিগার করে, কিছুই ফেরত না)।

# get the logger instance
logger = logging.getLogger("main_logger")
# configuration follows
...

এখন একটি সাব-মডিউলে, যদি আমরা নামকরণের ক্রম 'মেইন_লগার.সুব_মডিউল_লগার' অনুসারে একটি শিশু লগার তৈরি করি তবে আমাদের এটি সাব-মডিউলে কনফিগার করার দরকার নেই। নামকরণ শ্রেণিবদ্ধ অনুসরণ করে কেবলমাত্র লগার তৈরি যথেষ্ট।

# get the logger instance
logger = logging.getLogger("main_logger.sub_module_logger")
# no configuration needed
# it inherits the configuration from the parent logger
...

এবং এটি পাশাপাশি সদৃশ হ্যান্ডলার যুক্ত করবে না।

দেখুন এই একটি সামান্য আরো বাগাড়ম্বরপূর্ণ উত্তরের জন্য প্রশ্ন।


1
getLogger এর পরে পুনরায় সংজ্ঞায়িত হ্যান্ডলারগুলি আমার পক্ষে কাজ করছে বলে মনে হচ্ছে: logger = logging.getLogger('my_logger') ; logger.handlers = [logger.handlers[0], ]
Radtek

2

দ্বিগুণ (বা ট্রিপল বা ..- পুনরায় লোডের সংখ্যার উপর ভিত্তি করে) লগার আউটপুটও ঘটতে পারে যখন আপনি নিজের মডিউলটি পুনরায় লোড করবেন importlib.reload(গ্রহণযোগ্য উত্তরে বর্ণিত একই কারণে)। আমি এই উত্তরটি কেবলমাত্র ভবিষ্যতের রেফারেন্সের জন্য যুক্ত করছি কারণ আমার আউটপুটটি কেন দ্বৈত (ট্রিপল) রেখেছে তা নির্ধারণ করতে আমাকে কিছুটা সময় লেগেছে।


1

একটি সহজ workaround মত

logger.handlers[:] = [handler]

এইভাবে আপনি অন্তর্নিহিত তালিকার "হ্যান্ডলারগুলি" এ নতুন হ্যান্ডলার যুক্ত করা এড়াবেন।


1

বেশিরভাগ ক্ষেত্রে নীচের লাইনটি যখন এটি ঘটে তখন কেবলমাত্র মডিউল প্রতি একবার লগার .getLogger () কল করতে হবে। আমার মতো আপনার যদি একাধিক ক্লাস থাকে তবে আমি এটির মতো কল করতে পারি:

LOGGER = logger.getLogger(__name__)

class MyClass1:
    log = LOGGER
    def __init__(self):
        self.log.debug('class 1 initialized')

class MyClass2:
    log = LOGGER
    def __init__(self):
        self.log.debug('class 2 initialized')

তারপরে উভয়েরই নিজস্ব সম্পূর্ণ প্যাকেজের নাম এবং পদ্ধতি লগ ইন থাকবে method


0

আপনি নির্দিষ্ট লগারের জন্য সমস্ত হ্যান্ডলারের তালিকা পেতে সক্ষম হন, যাতে আপনি এর মতো কিছু করতে পারেন

logger = logging.getLogger(logger_name)
handler_installed = False
for handler in logger:
    # Here your condition to check for handler presence
    if isinstance(handler, logging.FileHandler) and handler.baseFilename == log_filename:
        handler_installed = True
        break

if not handler_installed:
    logger.addHandler(your_handler)

উপরের উদাহরণে আমরা যাচাই করেছিলাম কোনও নির্দিষ্ট ফাইলের হ্যান্ডলারটি ইতিমধ্যে লগারে আঁকা আছে কিনা, তবে সমস্ত হ্যান্ডলারের তালিকায় অ্যাক্সেস থাকা আপনাকে কোন মানদণ্ডে যুক্ত হওয়া উচিত বা অন্য কোনও হ্যান্ডলার যুক্ত করার সিদ্ধান্ত নেওয়ার ক্ষমতা দেয়।


0

আজ এই সমস্যা ছিল। যেহেতু আমার ক্রিয়াকলাপগুলি @staticmethod ছিল উপরোক্ত পরামর্শগুলি এলোমেলো () দিয়ে সমাধান করা হয়েছে।

এর মতো কিছু খুঁজছেন:

import random

logger = logging.getLogger('ProvisioningPython.{}'.format(random.random()))

-1
from logging.handlers import RotatingFileHandler
import logging
import datetime

# stores all the existing loggers
loggers = {}

def get_logger(name):

    # if a logger exists, return that logger, else create a new one
    global loggers
    if name in loggers.keys():
        return loggers[name]
    else:
        logger = logging.getLogger(name)
        logger.setLevel(logging.DEBUG)
        now = datetime.datetime.now()
        handler = logging.FileHandler(
            'path_of_your_log_file' 
            + now.strftime("%Y-%m-%d") 
            + '.log')
        formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        loggers.update(dict(name=logger))
        return logger

দীর্ঘমেয়াদী ব্যবহারের জন্য এই উত্তরটিকে আরও মূল্যবান করার জন্য দয়া করে ব্যাখ্যা যুক্ত করুন।
আমিনাহ নুরাইনি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.