Страницы

Поиск по вопросам

Показаны сообщения с ярлыком логирование. Показать все сообщения
Показаны сообщения с ярлыком логирование. Показать все сообщения

пятница, 13 марта 2020 г.

Передача логов по сети

#java #веб_программирование #логирование


Есть ли готовая реализация для передачи логов из java веб приложения по сети на другой
сервер? Или это делается как обычная передача файлов через сокет? В смысле, может быть
есть уже какая-то готовая библиотека для этого? 
    


Ответы

Ответ 1



Зависит от того, чем вы пользуетесь для логирования. Для Logback, например, существуют SocketAppender и SSLSocketAppender для отправки событий по сети, SyslogAppender для отправки на Syslog-сервер. Сервер для логирования через SocketAppender настраивается обычными средствами (XML) и запускается просто из командной строки: java ch.qos.logback.classic.net.SimpleSocketServer 6000 \ src/main/java/chapters/appenders/socket/server1.xml В Log4j 2 реализованы JMSAppender / KafkaAppender / ZeroMQ Appender для прокачки логов через очереди и аналогичные упомянутым выше SocketAppender и SyslogAppender.

Как отслеживать запуски GC и учитывать их при логировании из разных потоков?

#c_sharp #net #многопоточность #логирование


Из разных потоков вызывается метод и надо логировать его работу. Т.к. GC при сборке
мусора в WinForms и WPF приложениях может приостановить работу потоков приложения,
то это надо учитываться при логировании.
Как можно отслеживать запуски GC?
    


Ответы

Ответ 1



Для того чтобы отслеживать GC надо вызвать метод RegisterForFullGCNotification, а также WaitForFullGCApproach и WaitForFullGCComplete. using System.Diagnostics; using System.Collections.Concurrent; using System.Threading; using System.Runtime.CompilerServices; class LogLine { public int Number; public int ThreadId; public long Ticks; public object Value; public long GCMemory; public int[] GCCollections; public LogLine(int num, object value, long ticks) { this.Number = num; this.Value = value; this.Ticks = ticks; this.ThreadId = Environment.CurrentManagedThreadId; this.GCMemory = GC.GetTotalMemory(false); int[] arr = new int[GC.MaxGeneration + 1]; for (var i = 0; i < arr.Length; i++) arr[i] = GC.CollectionCount(i); this.GCCollections = arr; } } class Log : IDisposable { Stopwatch sw = Stopwatch.StartNew(); BlockingCollection lines = new BlockingCollection(); void Add(LogLine line) { if (!lines.IsAddingCompleted) lines.Add(line); } public Log() { GC.RegisterForFullGCNotification(1, 1); new Thread(() => { while (!lines.IsAddingCompleted) { Add(new LogLine(-1, GC.WaitForFullGCApproach(), sw.ElapsedTicks)); Add(new LogLine(-2, GC.WaitForFullGCComplete(), sw.ElapsedTicks)); } }).Start(); } public void WriteLine(object value = null, [CallerLineNumber] int cnumber = 0) { Add(new LogLine(cnumber, value, sw.ElapsedTicks)); } void IDisposable.Dispose() { GC.CancelFullGCNotification(); Add(new LogLine(-3, "Disposed", sw.ElapsedTicks)); lines.CompleteAdding(); } public IEnumerable ToCsv() { var s = ",\t "; yield return String.Concat( "Number", s, "Ticks", s, "ThreadId", s, "GCMemory", s, "GCCollections", s, "Value"); foreach (var l in lines) yield return String.Concat( l.Number, s, l.Ticks, s, l.ThreadId, s, l.GCMemory, s, String.Join(";", l.GCCollections), s, l.Value); } } Для теста в двух потоках создаем и заполняем список массивов по 100 тыс. int var log = new Log(); using (log) { Parallel.For(0, 2, i => { var lst = new List(); log.WriteLine("new List"); try { while (true) lst.Add(new int[100000]); } catch (OutOfMemoryException) { log.WriteLine("OutOfMemory; lst.Count=" + lst.Count); } }); } Выводим собранные данные foreach (var line in log.ToCsv()) Console.WriteLine(line); Результат (получен в C# Interactive, Microsoft (R) Roslyn C# Compiler version 1.1.0.51204) Number, Ticks, ThreadId, GCMemory, GCCollections, Value 55, 4030, 6, 6905852, 1;0;0, new List 55, 4426, 9, 6905852, 1;0;0, new List -1, 274370, 11, 1481676908, 6;5;5, Succeeded -2, 274430, 11, 1482877004, 6;5;5, Succeeded -1, 277392, 11, 1528080620, 6;5;5, Succeeded 58, 355462, 6, 1528087152, 8;7;7, OutOfMemory; lst.Count=1888 58, 355462, 9, 1528087152, 8;7;7, OutOfMemory; lst.Count=1920 -2, 317257, 11, 1528087152, 8;7;7, Succeeded -3, 356158, 6, 1528095344, 8;7;7, Disposed

воскресенье, 8 марта 2020 г.

Обработка ошибок: реализация текстовых сообщений и не только, поделитесь опытом, пожалуйста

#c_sharp #winforms #логирование


Заранее прошу прощения за несколько размытый вопрос, который может иметь, пожалуй,
несколько ответов, но всё-таки интересует прежде всего, практический аспект. 

Итак, имеется некий не очень большой проект, состоящий из ряда независимых модулей,
каждый вполне себе самостоятельный и написан разными людьми в разное время.

Часто в коде вижу различные (что естественно, imho) варианты отлова ошибок, от вполне
годных и уместных до просто try{...} catch{MessageBox.Show("Ошибка!");} (Да, и не такое
бывает), часто критичные места вообще без блоков try.

Задача стоит привести это дело (обработку ошибок) к какому-либо стандарту, хотя бы
в рамках данного проекта, и тут начинается веселье - во многих местах встречаются повторяющиеся
операции, например, при работе с файлами и каталогами, и в таких местах часто приходится
либо писать, либо уже есть конструкции вида:

     if (string.IsNullOrEmpty(path))
        {
            throw new ArgumentNullException(path, "Путь к каталогу должен быть задан.");
        }


Или же есть аналогичные конструкции, где при ошибочной ситуации возбуждается исключение
какого-либо типа (например, IOException) с каким-то текстовым описанием. При этом внутри
проекта нет (почти нет, честно говоря) какой-то своей иерархии классов для обработки
ошибок, используются штатные ошибки в основном.

Так вот, изначально был интересен взгляд на общую инфраструктуру обработки ошибок,
и подход в целом. Но этот аспект уже прояснил для себя. 

Но пока не очень понимаю, каким был бы наилучший подход с генерацией текстовых сообщений
ошибок как для модулей самого проекта, так и для логгера? (используется логгер, умеющий
работать с экземплярами Exception).

Пока первое, что пришло на ум - вынести все сообщения в отдельный файл в виде констант
и использовать их, подключая файл к каждому из модулей. Или может быть загнать всё
в ресурсы?

Но в целом интересны мнения сообщества, какие еще практические реализации и подходы,
методики были бы уместны и удобны в повседневном использовании с учетом описанного
контекста? Возможно, есть какие-то более эффективные, удобные и проверенные способы
или средства?

P.S. 


Локализации проекта на несколько языков — пока нет.
Вносить существенные изменения в код модулей не очень хотелось бы ("малой кровью"
обойтись бы).
Хотелось бы избежать сторонних решений, если, конечно они не решают задачу системно
и применимы в дальнейшем (вспомнился EurekaLog в Delphi).


Спасибо за внимание к вопросу!
    


Ответы

Ответ 1



Ошибки нужно отлавливать try/catch/finaly только в тех местах где они ожидаемы и только тех типов, которые ожидаются, банальный пример обращение к методу, в методе проверка на, к примеру, доступность этого вызова текущему пользователю, ожидаемое исключение скажем PermitionDeniedException, в блоке catch его и нужно отлавливать, остальное (например ArgumentNullException) должно пробрасываться на верх стека и обрабатывать "глобально", возможно тотальным крахом приложения. [System.Serializable] public class PermitionDeniedException : System.Exception { public PermitionDeniedException() : base("Пользователю не доступен этот метод") { } public PermitionDeniedException(string message) : base(message) { } public PermitionDeniedException(string message, Exception inner ) : base( message, inner ) { } protected PermitionDeniedException(SerializationInfo info, StreamingContext context) : base(info,context ) { } } try { SomeMethod(); } catch (PermitionDeniedException ex) { _logger.Error(ex, "Сообщение") } private static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) { var ex = e.ExceptionObject; if (ex.GetType() == typeof(ExceptionType1)) { _logger.Error(ex, "Сообщение"); // TODO: Уведомить пользователя } else if (ex.GetType() == typeof(ExceptionType2)) { _logger.Fatal(ex, "Сообщение"); // Экстренно завершить приложение } else { _logger.Fatal(ex, "Сообщение"); // Можно сделать дамп и завершить приложение } } Для Winforms, где-то в методе Main наверное стоит подписать на AppDomain.UnhandledException Например так: System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper; В обработчике UnhandledExceptionTrapper можно получить тип исключения, проверить его критичность и в зависимости от нее (критичности) либо экстренно свалиться, сообщив пользователю что то вроде "Программа выполнила недопустимую ошибку и будет закрыта" или же продолжить работу, но опять же известив пользователя. Что касается мультиязычности, то тут нужны динамические ресурсы и словари ресурсов, в них можно хранить строки, которыми можно описать исключение. П.С. Структуру исключении стоит продумать, она может быть и одноуровневой, что скорее даже плюс. Максимально общие (корни) необходимо наследовать от System.Exception, что писать в сообщении придумать тоже не сложно, если у вас продуманная структура исключений. Для логирования ошибок лучше всего использовать готовые логгеры, или Trace. Последний не такой гибкий, зато ничего из nuget тащить не нужно. Из готовых последнее время сам пользуюсь NLog. Несколько сумбурно на мой взгляд, поэтому буду рад критике.

Android logcat не работает

#android #android_sdk #gradle #логирование #logcat


Отлаживаю приложение через USB, Android Studio не пишет ничего в logcat. Раньше все
было отлично, но сейчас вообще не идет никакой информации даже если убрать фильтры.
Копался в Функциях для разработчиков на смартфоне, ничего не нашел. 

вот это я нашел:


    


Ответы

Ответ 1



Если вы запускаете релизную сборку приложения, то у вас, скорее всего, не прописано в gradle debuggable true для неё. buildTypes { release { debuggable true } } Второй вариант включения логов в релизной сборке - указать этот атрибут в манифесте через атрибут тега Application android:debuggable="true" Самый же лучший вариант - настроить варианты для сборки так, чтобы иметь возможность включать/выключать логи для релизной сборки в разных оной вариантах так: buildTypes { debug { resValue "bool", "debuggable", "true" } release { } } productFlavors { dev { resValue "bool", "debuggable", "true" } prod { resValue "bool", "debuggable", "false" } } В манифесте укажите ссылку на сгенерированный градлом ресурс: android:debaggable="@bool/debuggable" Теперь вы сможете собирать devRelease сборку с включёнными логами и prodRelease с выключенными. А debug сборки всегда будут с включёнными логами

Ответ 2



Включите это в Android Studio: Tools -> Android -> Enable ADB Integration

воскресенье, 9 февраля 2020 г.

Можно ли писать прямиком в syslog?

#linux #c #логирование


Можно ли делать запись прямиком в /dev/log как в /dev/stdout? Например так:

echo test > /dev/log


У меня вылетает ошибка:


  bash: log: Нет такого устройства или адреса.


Если это вообще возможно, то что я делаю не так?
    


Ответы

Ответ 1



Мне надо писать в syslog внутри библиотеки используется write() Это кто Вас надоумил так делать?! :-) Два момента. Первый: $ ls -l /var/log/sys* -rw-r----- 1 syslog adm 20148 окт 8 09:05 /var/log/syslog -rw-r----- 1 syslog adm 380325 окт 8 08:22 /var/log/syslog.1 -rw-r----- 1 syslog adm 46102 окт 7 08:25 /var/log/syslog.2.gz -rw-r----- 1 syslog adm 51345 окт 4 08:26 /var/log/syslog.3.gz -rw-r----- 1 syslog adm 212595 окт 3 08:47 /var/log/syslog.4.gz -rw-r----- 1 syslog adm 71915 окт 1 08:28 /var/log/syslog.5.gz -rw-r----- 1 syslog adm 54724 сен 30 08:23 /var/log/syslog.6.gz -rw-r----- 1 syslog adm 82350 сен 27 08:29 /var/log/syslog.7.gz Понимаете, что это означает? То, что писать в этот файл может только демон syslog, а читать - только он и члены группы adm. Так что, записать с помощью write() у Вас не получится никак. Без прав root. Второе. Для того, что бы пользоваться услугами демона syslog существует набор стандартных системных функций: void openlog(const char *ident, int option, int facility); void syslog(int priority, const char *format, ...); void closelog(void); А тех программистов, которые пишут свои собственные "лог-файлы" с использованием write() я считаю не очень уными людьми. Ведь достаточно просто выполнить команду man 3 syslog и можно посмотреть готовое решение проблемы. Особенно не люблю программёров, которые сообщения об ошибках и отладочные сообщения выдают с помощью printf(). Когда в службу поддержки обращается клиент и говорит, что у него ВЧЕРА было что-то непонятное с программой, то эти сообщения в ЕГО stderr исчезнувшие ещё вчера - представляют просто таки "бесценную" помощь для программиста сопровождения. На самый крайний случай, если заменить write() на syslog() нет никакой возможности, рекомендую попробовать такой метод: Пишем программу, которая: С помощью inotify (man 7 inotify) устанавливает слежение за файлом, в который исходная программа пишет сообщения. Получив уведомление о записи в этот файл, программа считывает добавленный кусок текста. Это можно сделать, зная исходную и новую длину файла. Записывает полученный текст в системный лог, используя syslog().

Ответ 2



Linux команда logger даёт удобный способ писать в системный лог /var/log/syslog из командной строки, из скриптов или других файлов $ logger comment to be added to log $ tail -1 /vvar/log/syslog May 21 18:02:16 butterfly shs: comment to be added to log $ logger `who` $ tail -1 /var/log/syslog May 21 18:02:43 butterfly shs: shs pts/0 2018-05-21 15:57 (192.168.0.15) $cat msg Backups to off-site facility will run this coming weekend. System availability will not be affected. $ logger -f msg $ tail -2 /var/log/syslog May 21 18:06:01 butterfly shs: Backups to off-site facility will run this coming weekend. May 21 18:06:01 butterfly shs: System availability will not be affected

пятница, 24 января 2020 г.

Как в .NET Core установить другой уровень ведения логов

#c_sharp #aspnet_core #логирование


Не могу понять — вроде делаю всё правильно. Но почему то в логи .NET Core пишет сообщения
уровня Information. Хотя я явно указал в настройках писать только Error.
Вот часть Program.cs:

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup()
        .ConfigureLogging((hostingContext, logging) =>
        {
            logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
        })
        .Build();


Конфиг appsettings.json выглядит так:

"Logging": {
  "IncludeScopes": false,
  "LogLevel": {
    "Default": "Error"
  }
}


Что я делаю не правильно?
    


Ответы

Ответ 1



Разобрался... Причина была в том, что в директории приложения был файл appsettings.Development.json и настройки логгирования брались из него а не из appsettings.json, причем этот фал в обозревателе VisualStudio не было видно, а я и не догадался сам сходить в директорию приложения и посмотреть что там есть. Откуда этот файл и кто его создал непонятно.

Вывод в окне QPlainTextEdit pyqt5 сообщения из модуля logging.Поток pyqt5.Логирование

#python #многопоточность #pyqt5 #логирование


Как сделать так что-бы сообщения из модуля logging выходили в окне QPlainTextEdit.Желательно
показать на моём примере как из потока вывести сообщение по завершению действия функции,так
и без потока.По сути логирование программы.


# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'stacword.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!
import logging
import sys
from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(316, 324)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(110, 240, 75, 23))
        self.pushButton.setObjectName("pushButton")
        self.plainTextEdit = QtWidgets.QPlainTextEdit(self.centralwidget)
        self.plainTextEdit.setGeometry(QtCore.QRect(10, 10, 291, 131))
        self.plainTextEdit.setObjectName("plainTextEdit")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(130, 180, 47, 13))
        self.label.setObjectName("label")
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))
        self.label.setText(_translate("MainWindow", "TextLabel"))


class ExampleApp(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()

        self.setupUi(self)

        self.plainTextEdit.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
# Делает QPlainTextEdit только для вывода

        self.thread = WorkThread()

        self.pushButton.clicked.connect(self.func1)

        logging.basicConfig(level=logging.DEBUG)

        logging.info(u'This is an info message')

    def func1(self):
        # Создаем поток
        self.thread.start()


class WorkThread(QtCore.QThread):
    ''' Потоковая задача '''
    threadSignal = QtCore.pyqtSignal(int)

    def __init__(self):
        super().__init__()

    def run(self):     # После окончания работы этой фукции в потоке,вывести сообщение
от модуля logging в QPlainTextEdit
        for i in range(10):
            self.msleep(200)
            print(i)
            self.threadSignal.emit(i)


def main():
    app = QtWidgets.QApplication(sys.argv)  # Новый экземпляр QApplication
    window = ExampleApp()  # Создаём объект класса ExampleApp
    window.show()  # Показываем окно
    app.exec_()


if __name__ == '__main__':
    main()


    


Ответы

Ответ 1



Как вариант: import logging import sys from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(316, 324) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(110, 240, 75, 23)) self.pushButton.setObjectName("pushButton") self.plainTextEdit = QtWidgets.QPlainTextEdit(self.centralwidget) self.plainTextEdit.setGeometry(QtCore.QRect(10, 10, 291, 131)) self.plainTextEdit.setObjectName("plainTextEdit") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(130, 180, 47, 13)) self.label.setObjectName("label") MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "PushButton")) self.label.setText(_translate("MainWindow", "TextLabel")) # +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv class QTextEditLogger(logging.Handler): def __init__(self, parent): super().__init__() self.widget = parent.plainTextEdit self.widget.setReadOnly(True) def emit(self, record): msg = self.format(record) self.widget.appendPlainText(msg) # +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ class ExampleApp(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) # +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv logTextBox = QTextEditLogger(self) logTextBox.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logging.getLogger().addHandler(logTextBox) logging.getLogger().setLevel(logging.DEBUG) # +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # Делает QPlainTextEdit только для вывода self.plainTextEdit.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) self.thread = WorkThread() self.thread.threadSignal.connect(self.func2) # +++ self.pushButton.clicked.connect(self.func1) logging.debug("Это сообщение об отладке") logging.info(u'This is an info message') def func1(self): # Создаем поток self.thread.start() def func2(self, value): # +++ logging.info("Передано из потока -> {}".format(value)) # +++ class WorkThread(QtCore.QThread): ''' Потоковая задача ''' threadSignal = QtCore.pyqtSignal(int) def __init__(self): super().__init__() def run(self): for i in range(10): self.msleep(200) # print(i) self.threadSignal.emit(i) def main(): app = QtWidgets.QApplication(sys.argv) window = ExampleApp() window.show() app.exec_() if __name__ == '__main__': main() каким образом можно вывести сообщение по завершению действия в потоке? import logging import sys from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(400, 324) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(110, 240, 75, 23)) self.pushButton.setObjectName("pushButton") self.plainTextEdit = QtWidgets.QPlainTextEdit(self.centralwidget) self.plainTextEdit.setGeometry(QtCore.QRect(10, 10, 370, 131)) self.plainTextEdit.setObjectName("plainTextEdit") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(130, 180, 47, 13)) self.label.setObjectName("label") MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "PushButton")) self.label.setText(_translate("MainWindow", "TextLabel")) class QTextEditLogger(logging.Handler): def __init__(self, parent): super().__init__() self.widget = parent.plainTextEdit self.widget.setReadOnly(True) def emit(self, record): msg = self.format(record) self.widget.appendPlainText(msg) class ExampleApp(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) logTextBox = QTextEditLogger(self) logTextBox.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logging.getLogger().addHandler(logTextBox) logging.getLogger().setLevel(logging.DEBUG) layout = QtWidgets.QVBoxLayout(self.centralwidget) # +++ layout.addWidget(self.plainTextEdit) layout.addWidget(self.label) layout.addWidget(self.pushButton) self.plainTextEdit.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) self.thread = WorkThread() self.thread.threadSignal.connect(self.func2) self.thread.finishSignal.connect(self.func3) # +++ self.pushButton.clicked.connect(self.func1) logging.debug("Это сообщение об отладке") logging.info('This is an info message') def func1(self): # Создаем поток self.thread.start() def func2(self, value): logging.info("Передано из потока -> {}".format(value)) def func3(self): logging.info("Программа зевершена") class WorkThread(QtCore.QThread): ''' Потоковая задача ''' threadSignal = QtCore.pyqtSignal(int) finishSignal = QtCore.pyqtSignal() # +++ def __init__(self): super().__init__() def run(self): for i in range(10): self.msleep(200) self.threadSignal.emit(i) self.finishSignal.emit() # +++ def main(): app = QtWidgets.QApplication(sys.argv) window = ExampleApp() window.show() app.exec_() if __name__ == '__main__': main()

суббота, 11 января 2020 г.

Логирование в разные файлы

#java #логирование


Есть такой properties файл

.level = FINE
my.handlers = java.util.logging.ConsoleHandler
my.name1.handlers = java.util.logging.FileHandler
my.name2.handlers = java.util.logging.FileHandler

java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = my.log.LogFormatter
java.util.logging.FileHandler.formatter = my.log.LogFormatter
java.util.logging.FileHandler.pattern = log_%u.log


Вопрос, можно ли как-то развести по разным файлам логи от my.name1 и my.name2?

Или только написанием наследника FileHandler с перекрытием метода publish?
    


Ответы

Ответ 1



В общем случае конфигурацией вы вашу задачу не решите. Если вы конфигурируете логирование Tomcat, то там такая возможность есть. Если нет - можно этого добиться, сконфигурировав логгеры в Java: Logger log1 = Logger.getLogger("my.name1"); log1.addHandler(new FileHandler("my.name1.log")); Logger log2 = Logger.getLogger("my.name2"); log2.addHandler(new FileHandler("my.name2.log")); Если есть такая возможность, постарайтесь отказаться от java.util.logging в пользу более гибкой библиотеки логирования. В log4j и Logback возможность разводить разные логи в разные файлы есть из коробки. А если вы воспользуетесь slf4j, то сможете при необходимости относительно безболезненно сменить библиотеку логирования, не модифицируя код.

пятница, 10 января 2020 г.

Как настроить Log4Net, что бы было определенное кол-во логов?

#c_sharp #net #логирование #log4net


Сейчас имеется такая конфигурация:

 
    
      
      
    
    
      
      
      
      
      
        
      
    
    
      
      
      
    
  


По сути, на каждый запуск программы создается свежий лог.

Однако, хоть и указано, что нужно хранить 3 лога, то логи все равно копятся больше 3.

Можно ли это пофиксить или нужно ручками чистить?
    


Ответы

Ответ 1



Проблема связана, очевидно, с тем, что у Вас имена файлов лога основаны на шаблоне с датой. Причём формат даты такой, что ограничение на количество файлов лога будет иметь значение только в пределах 1 секунды. Проще говоря, логи будут чиститься сами только если их количество будет превышать 3 файла в секунду и удаляться будут именно те, которые были записаны в эту секунду первыми. Смотрим документацию: The maximum applies to each time based group of files and not the total. Возможное решение (на уровне патча) есть тут, сам не пробовал. Рекомендовал бы поэкспериментировать с этим и попробовать изменить шаблон имени файла, ограничив, например, 1 днём. Таким образом, если в течении дня будет записано более 3 файлов - должно произойти усечение.

понедельник, 6 января 2020 г.

Сохранение логов после перезагрузки системы

#linux #логирование


Есть приложение на с++, которое пишет данные в лог.

Используется syslog(LOG_INFO,"Init"), к примеру. Данные записываются в /var/log/messages.

При перезагрузке системы данные из /var/log/messages удаляются. 
Есть ли способ сделать так, чтобы логи не удалялись? Предполагаю, что нужно использовать
syslog.conf.

Как можно решить проблему?

Операционная система: busybox/linux.
    


Ответы

Ответ 1



это, вероятно, т.н. «embedded»-система. и каталог /var (или только /var/log) находится на временной файловой системе (скорее всего, типа tmpfs), которая расположена в оперативной памяти, и создаётся при загрузке системы. пример проверки (это дистрибутив openwrt): $ df /var Filesystem 1K-blocks Used Available Use% Mounted on tmpfs 63268 380 62888 1% /tmp $ ls -ld /var lrwxrwxrwx 1 root root 4 Sep 17 2013 /var -> /tmp делается это с целью сохранения ресурса накопителя информации, который в таких устройствах обычно может выдержать довольно ограниченное количество операций записи. не зная подробностей об используемом вами дистрибутиве, могу предположить лишь такие общие варианты решения: изменить вашу программу, чтобы она писала данные в файл, расположенный на блочном устройстве хранения информации; изменить систему инициализации вашего дистрибутива так, чтобы каталог /var или /var/log или хотя бы файл /var/log/messages располагался не в памяти, а на блочном устройстве; изменить конфигурацию используемого вами системного логгера так, чтобы он записывал не в файл /var/log/messages, а в файл, расположенный на блочном устройстве. или, например, отсылал логируемую информацию по сети на другой компьютер.

суббота, 4 января 2020 г.

Как логировать работу программы с помощью ETW?

#c_sharp #net #clr #логирование


Информация о работе .NET выводится в ETW (Event Tracing for Windows) и ее можно получить
с помощью программы PerfView.
Как из приложения выводить свою информацию в ETW?
И возможно ли выводить 100 тыс. сообщений в секунду? 
    


Ответы

Ответ 1



ETW позволяет выводить до 500 тыс. сообщений в секунду с минимальными затратами. Например, надо в ETW выводить уведомления о ходе выполнения, а также информацию о начале и завершении какой-то активности. Для этого надо определить класс, производный от EventSource. using System.Diagnostics.Tracing; [EventSource(Name = "MyApp")] class MyAppEvent : EventSource { public static MyAppEvent Log = new MyAppEvent(); [Event(1)] // уведомление о ходе выполнения public void Progress(int v, string msg) { WriteEvent(1, v, msg); } [Event(2, Opcode = EventOpcode.Start)] // начало активности public void StartAction(int id) { WriteEvent(2, id); } [Event(3, Opcode = EventOpcode.Stop)] // завершение активности public void StopAction(int id) { WriteEvent(3, id); } } для вывода в ETW пишем partial class MainWindow : Window { public MainWindow() { var log = MyAppEvent.Log; ... log.Start(1); log.Progress(1, "ok"); log.Stop(1); Компилируем и из командной строки запускаем PerView > PerfView /OnlyProviders=*MyApp run WpfApplication.exe В результате создается PerfViewData.etl.zip, в котором находится файл PerfViewData.etl - его можно открыть в PerfView и посмотреть информацию, например, по вызовам Start.

вторник, 31 декабря 2019 г.

Логирование ошибок

#java #android #логирование


Здравствуйте!
Не подскажете, каким способом логировать ошибки в Android-приложениях?
Каким способом лучше отправлять с аппарата на сервер разработчика сообщения об ошибке
в приложении?
Я думаю, что стоит писать все в файл и отправлять на сервер через время, если есть
необходимость. Но как отловить все ошибки в приложении, пока не знаю.
Что можете посоветовать?    


Ответы

Ответ 1



Для отлова есть библиотека Acra. Отлавливает абсолютно всё + есть возможность для отправки баг репорта программисту-создателю. Вот мини-гайд. А для логирования slf4j, правда, как она дружит/недружит с андроидом, я хз.

Ответ 2



Я рекомендую Crashlytics. Есть возможность кидать сообщения об исключениях, фатальных ошибках и т.д. Есть возможность создавать команды, давать роли: программисты, тестеры. В общем, очень удобный аналог Test Flight (iOS) только для Android.

Как эффективнее всего распарсить огромный файл логов на слабой машине?

#алгоритм #файлы #логирование #highload #big_data


Есть сервер с 1gb RAM. Есть лог файл nginx (любой другой веб-сервер) на 70gb. Как
максимально быстро собрать статистику по user agent пользователей сайта, учитывая описанные
ограничения по ресурсам.
    


Ответы

Ответ 1



можно воспользоваться StringTokenizer в языке Java, который позволяет считывать файл построчно и не тратить память на хранение всех строк файла. StringTokenizer tok = new StringTokenizer("/path/to/file"); while (tok.hasMoreTokens()) { String line = tok.nextToken(); // работаешь со строкой. } Также можно указывать разделитель в конструкторе, по умолчанию стоит \t\n\r\f

Ответ 2



Считываете файл построчно и анализируете считанную сроку. Практически во всех языках можно указать размер буфера при работе с файловой системой и поэтому, несмотря на то, что вы работаете с файлом построчно, система будет читать файл фиксированными блоками.

воскресенье, 29 декабря 2019 г.

Метод Trace.TraceInformation(string)?

#c_sharp #net #юнит_тесты #отладка #логирование


Для чего и как используется этот метод?

[TestMethod]
public void Q_GetAllCustomers_NoExc()
{
     foreach(var i in context.GetAll())
     {
          Trace.TraceInformation($"{i.FirstName} {i.LastName}")
     }
}


Куда попадёт string, который я передаю этому методу. И как это вообще связано с TDD?
    


Ответы

Ответ 1



Это встроенное средство отладки, трассировочное сообщение. У вас есть конфигурируемый через app.config (или вручную) список слушателей трассировочных сообщений. Им и доставляется полученная строка. Например, вы можете направить ваши трассировочные сообщения в файл или на консоль, положить в системный event log, отправить по сети или положить на web-страницу. В случае, если вы запускаете проект из-под Visual Studio, ваши трассировочные сообщения слушает IDE, и показывает их в окошке Debug. В случае, когда вы запускаетесь не из-под Visual Studio, трассировочные сообщения уходят системе (если вы не отконфигурировали по-другому). Вы можете их видеть при помощи, например, утилиты DebugView. С TDD не связано никак.

Ответ 2



В дополнение к ответу @VladD добавлю, что в случае с запуском теста из-под Visual Studio, вся отладочная и трассировочная информация также доступна в тест аутпуте:

Ответ 3



Куда попадёт string, который я передаю этому методу. Если компиляция проходила при включенном TRACE, то зависит от того какие TraceListener'ы подключены. Посмотреть можно так: using System.Linq; using System.Diagnostics; for(var i=0; i < Trace.Listeners.Count; i++) { Console.WriteLine(Trace.Listeners[i].GetType().Name); } при выполнении кода в C# interactive выводится DefaultTraceListener. Коллекцию Trace.Listeners можно менять, и например, если требуется выводить информацию в файл, после запуска приложения вызываем: Trace.Listeners.Add(new TextWriterTraceListener(@"c:\temp\trace.txt")); Дальше, где-бы ни находился вызов Trace.TraceInformation("test"); в файл выводит test вместе с именем процесса. Формат вывода можно настроить и выводить время, идентификатор потока и т.д.

суббота, 28 декабря 2019 г.

архивация логов

#linux #логирование


есть каталог /var/log.

как с помощью с скрипта заархивировать логи старше, чем вчера, в папку /var/log/archive?

логи имеют формат yyyy_mm_dd_name.log
    


Ответы

Ответ 1



главные трудности, видимо, следующие: отобрать только те файлы в текущем каталоге, имена которых соответствуют шаблону yyyy_mm_dd_name.log, где name — произвольный набор символов, не содержащий символа _ исключить из отобранных те файлы, в именах которых часть yyyy_mm_dd соответствует сегодняшней или вчерашней дате что-то сделать с найденными файлами (например, переместить куда-нибудь) решение: отобрать в текущем каталоге такие файлы можно, например, так: $ find -maxdepth 1 -regextype posix-basic -regex "\./[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}_[^_]\+\.log" проверим, создав тестовые файлы (один содержит сегодняшнюю дату, один — вчерашнюю, один — позавчерашнюю, и один, контрольный, не содержит даты в имени): $ touch 2016_07_04_some.log 2016_07_03_some.log 2016_07_02_some.log some.file $ find -maxdepth 1 -regextype posix-basic -regex "\./[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}_[^_]\+\.log" ./2016_07_03_some.log ./2016_07_04_some.log ./2016_07_02_some.log вроде, правильно. чтобы исключить файлы, в имени которых содержится сегодняшняя или вчерашняя дата, надо добавить к опциям программы find такую примерно конструкцию: \! -regex "\./2016_07_04_[^_]\+\.log" \! -regex "\./2016_07_03_[^_]\+\.log" тогда в вывод попадает только позавчерашний файл: ./2016_07_02_some.log но завтра ведь даты будут другие. как привязаться к текущему дню? с помощью программы date, например. сегодняшняя дата: $ date +'%Y_%m_%d' 2016_07_04 и вчерашняя: $ date -d 'day ago' +'%Y_%m_%d' 2016_07_03 заключаем вызовы date в «операторные скобки» $(...), подставляем в нужные места, и получаем длинную команду: $ find -maxdepth 1 -regextype posix-basic -regex "\./[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}_[^_]\+\.log" \! -regex "\./$(date +'%Y_%m_%d')_[^_]\+\.log" \! -regex "\./$(date -d 'day ago' +'%Y_%m_%d')_[^_]\+\.log" ./2016_07_02_some.log для того, чтобы переместить найденные программой find файлы в каталог, например, /var/log/archive, можно добавить к опциям той же программы такую, например, конструкцию: -exec mv {} /var/log/archive \; итого полный текст команды будет таким: $ find -maxdepth 1 -regextype posix-basic \ -regex "\./[0-9]\{4\}_[0-9]\{2\}_[0-9]\{2\}_[^_]\+\.log" \ \! -regex "\./$(date +'%Y_%m_%d')_[^_]\+\.log" \ \! -regex "\./$(date -d 'day ago' +'%Y_%m_%d')_[^_]\+\.log" \ -exec mv {} /var/log/archive \; он разбит на строки исключительно для удобства обзора. если вставлять этот текст в одну строку, то последний в каждой строке символ \ надо удалить.

Ответ 2



Не нужно писать собственное решение, когда уже есть различные готовые. Автоматическая ротация и архивация логов Решение называется logrotate. Предположим, вы хотите ротировать и архивировать логи приложения name Конфигурация в файле /etc/logrotate.d/name: /var/log/*name.log { daily # ежедневно olddir /var/log/archive # перемещать в другую папку missingok # не создавать сообщение об ошибке, если лог пустой } Logrotate исключает необходимость приложению самостоятельно записывать дату в имя файла. Приложение может писать логи в один и тот же файл, который в момент ротации будет заменяться на новый. Если приложение самостоятельно не переоткрывает файл при записи каждой новой строки, то будет полезна опция copytruncate. С ней logrotate не пересоздает файлы логов, а вырезает содержимое и пишет его в новый файл. /var/log/*name.log { ... copytruncate } copytruncate Truncate the original log file in place after creating a copy, instead of moving the old log file and optionally creating a new one, It can be used when some program can not be told to close its logfile and thus might continue writing (appending) to the previous log file forever. Если по соображениям места на диске или полезности вы хотите хранить логи за последние N периодов ротации, то добавьте опцию rotate N. Например, за последнюю неделю: /var/log/*name.log { ... daily rotate 7 } Централизованное хранение логов. Хранить важные логи прямо на хосте - это плохо, и вот почему: Там может быть недостаточно места. У меня был случай, когда логи заняли всё место и парализовали хост (к счастью, тестовый). Если всё совсем сломается, то логи будут очень нужны, а вы на них не посмотрите. Читать логи в текстовом редакторе или анализировать grep'ом - неэффективно. У этого способа масштабируемость хуже линейной. То есть чтобы следить за логами на вдвое большем количестве хостов вам понадобится более чем вдвое больше ресурсов (человекочасов и т.п.). Логи должны храниться централизованно и в базе данных. Тогда: Вы можете получать оперативную аналитику Вы можете легко сравнивать логи между разными хостами, приложениями, периодами времени В случае поломки все или почти все логи будут вам доступны Масштабируемость примерно логарифмическая. Есть ряд решений, одно из них - стек ELK (Elasticsearch, Logstash, Kibana). Возможно, в данный момент для ваших задач достаточно простой ротации. Но, пожалуйста, ориентируйтесь на централизованное хранение.

понедельник, 23 декабря 2019 г.

Логгирование в журнал событий ОС с помощью NLog

#c_sharp #логирование #nlog


Добрый день, только недавно начал использовать Nlog, довольно быстро в нем разобрался,
но не смог понять как писать логи в журнал событий WIndows (7).

Нужно ли что-то дописывать в конфиг файл?

Как писать логи в ОС с помощью System.Diagnostic я знаю, но хотелось бы использовать
для этого NLog. Заранее спасибо.
    


Ответы

Ответ 1



Вам сюда (пример оттуда):

воскресенье, 22 декабря 2019 г.

Как можно проследить последовательность вызовов методов в Android приложении

#java #android #android_studio #логирование


Как можно развернуть во времени событийную последовательность вызова процедур указанных
классов приложения? На примере Activity lifecycle, в onCreate, onResume, onPause  и
т.д. - в каждый метод можно вручную вставлять вызов Log.d. В LogCat после чего становится
понятна последовательность вызовов. Подобное хотелось бы осуществлять в других классах
исходных примеров, в которых может быть намного больше методов. Имеется ли автоматизация
Log.d или аналогичный инструментарий? Методом trace получается много излишней информации
над которой требуются дополнительные манипуляции при изучении. Или trace все же единственный
подходящий способ?!
    


Ответы

Ответ 1



Можно воспользоваться Аспектно - Ориентированным Программированием. Добавить зависимости: build.gradle dependencies { ... classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.14' } app/build.gradle apply plugin: "android-aspectj" ... dependencies { ... compile 'org.aspectj:aspectjrt:1.8.9' } Написать аспект: LogAspect.java @Aspect public class LogAspect { private static final String TAG = "aspect"; @Before("execution(* *(..)) ") public void doBeforeAyMethod(JoinPoint joinPoint) { if(joinPoint.getTarget() != null) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); Log.i(TAG, joinPoint.getTarget().getClass().getSimpleName() + " : " + method.getName()); } } } Теперь все методы классов вашего приложения пропишутся в лог. Стоит помнить, что это сработает с методами непосредственно находящимися в классе, методы суперкласса не упадут в лог, только если они будут переопределены. А если написать свою аннотацию, например: MethodLog.java @Target(ElementType.TYPE) public @interface MethodLog { } Проаннотировать ею нужные классами, и добавить в аспект: @Before("execution(* *(..)) && @within(MethodLog)") В лог упадут методы только выбранных классов.

четверг, 5 декабря 2019 г.

Логирование lua в syslog

#linux #логирование #lua


Как напрямую писать логи с Openresty Lua в syslog?

При установке библиотеки luasyslog возникает ошибка:

ng-gateway_1  | error loading module 'vendors.lsyslog' from file '/usr/local/openresty/site/lualib/vendors/lsyslog.so':
ng-gateway_1  |     /usr/local/openresty/site/lualib/vendors/lsyslog.so: undefined
symbol: luaopen_vendors_lsyslog


Подскажите как решить проблему, или какую библиотеку использовать.
Спасибо!
    


Ответы

Ответ 1



Было принято решение писать в syslog сервера на уровне nginx. В docker-compose в volumes добавил bind на локальный /dev/log: - type: bind source: /dev/log target: /dev/log В nginx.conf, директиве server прокинул 2 unix socket-а: # Logging configurations error_log syslog:server=unix:/dev/log,tag=ng_trace; access_log syslog:server=unix:/dev/log,tag=ng_trace,nohostname; Для логирования в lua использую ngx.log(ngx.ERR, 'Log message') Все логи из докер-контейнера пишутся прямиком в syslog сервера.

Ответ 2



Openresty не пользовал, поэтому за правильность ответа - не ручаюсь. По приведенным логам ситуация похожа на не согласование версий. Возможно отрывок из FAQ Openresty ситуацию прояснит: ** Why can't I use Lua 5.2 or later? ** Lua 5.2+ are incompatible with Lua 5.1 on both the C API land and the Lua land (including various language semantics). If as you said there are quite a few people already using ngx_lua + Lua 5.1, then linking against Lua 5.2+ will probably break these people's existing Lua code. Lua 5.2+ are essentially incompatible different languages. Supporting Lua 5.2+ requires nontrivial architectural changes in ngx_lua's basic infrastructure. The most troublesome thing is the quite different "environments" model in Lua 5.2+. At this point, we would hold back adding support for Lua 5.2+ to ngx_lua. Also, we do not want to create confusions and incompatibilities on the Lua land for applications running atop ngx_lua, as well as all the existing lua-resty-* libraries written in the Lua 5.1 language. We believe it is better to stick with one Lua language in ngx_lua. Chasing the Lua language's version number has not many practical technical merits (if there were some political ones). Резюме: смотрите версию используемого Lua

четверг, 28 ноября 2019 г.

О логировании в java

#java #логирование


Приводится на хабре в статье библиотека Apache Commons Logging (не знаю смысл этой
библиотеки,  не юзал) и комментарий:


  За System.out.println для вывода логов начинающим программистам уже через неделю
обучения следует отрубать руки.


Так вот вопрос: а почему print настолько плох?

P.S. Сам я основы языка очень плохо знаю.
    


Ответы

Ответ 1



Логирование - это все-таки больше, чем вывод строк в консоль. Здесь имеют место следующие параметры: Цель: это может быть консоль (stdout), немного другая консоль (stderr), файл, удаленный сервер сбора логов Уровень логирования: для разных выводов может быть разный уровень вывода: например, в один файл мы скидываем всё, но храним только последние десять мегабайт, а в другой отправляем только сообщения уровня WARN и выше, но храним историю за последние шесть месяцев Per-package настройки: в случае, если "шалит" конкретный участок кода, можно включить логирование только для него Ротация логов: логи чаще всего надо хранить в файлах, которые нужно периодически подчищать, и при этом во время проведения работ продолжать писать логи Контекст выполнения: зачастую просто сообщения недостаточно (если транзакция провалилась, то какие входные параметры этому поспособтсвовали?), поэтому существуют штуки типа MDC, чтобы при обработке конкретного юзера перед каждым вашим сообщением добавлялась мапа {processed user id: 12345} Подстановка параметров: писать Logger.debug("Transaction #{} has failed with message '{}'", transaction.getId(), e.getMessage()) гораздо удобнее, чем писать System.out.ptintln("Transaction #" + transaction.getId() + " has failed with message '" + e.getMessage() + "'"). Кроме удобства, это позволяет не конкатенировать строки, если уровень логирования выше самого сообщения (т.е. при уровне INFO сообщения с уровнем DEBUG не будут тратить ресурсы на конкатенацию) и группировать лог-сообщения по шаблону (искать в логах вместо просто слова "transaction" конкретный шаблон). Всем этим занимается библиотека логирования, и она сильно упрощает жизнь, когда нужно перейти от одной модели к другой, например, когда логи возле приложения хранить стало нецелесообразно, для переключения на удаленный сервер достаточно подключить новый аппендер и перезапустить приложение. Кроме того, существует ситуация, когда логов настолько много, что I/O не успевает справляться - о проблемах такого рода, как правило, не думают вплоть до их появления, а в библиотеках (я надеюсь) некоторые предусмотрительные шаги уже сделаны (например, logback совершенно точно по умолчанию пытается добавить сообщение пять раз на тот случай, если что-то пошло не так).

Ответ 2



По сути, выше уже всё было сказано, добавлю ещё один практический аспект. Консоль имеет определённую емкость. И, например, если она равна 300 строк, то в случае, если в неё запишутся 500 строк, начальные 200 строк вы уже не увидите. Можно, конечно, увеличить размер буфера консоли, но тогда придётся его увеличивать постоянно, а это не лучший вариант. Особенно для большого проекта, где логи записываются практически непрерывно, и логируется большой объём данных.

понедельник, 8 июля 2019 г.

Best Practise - python logger.debug различные yровни логгирования debug

Какие существуют рекомендации по написанию логгирования для режима debug в коде? Как правильно реализовать различные уровни (от 1 до 5 по уровню деталиазации) логгирования для указного режима? Например при включении debug_level <= 3 выводить сообщения в файл логгирования, а если debug_level > 3 тогда выводить debug информацию только на консоль.


Ответ

Привожу простой пример логгирования в консоль и файл с кастомный форматом логов:
def get_logger(name, file='log.txt', encoding='utf8'): import sys import logging
log = logging.getLogger(name) log.setLevel(logging.DEBUG)
formatter = logging.Formatter('[%(asctime)s] %(filename)s[LINE:%(lineno)d] %(levelname)-8s %(message)s')
fh = logging.FileHandler(file, encoding=encoding) fh.setLevel(logging.DEBUG)
ch = logging.StreamHandler(stream=sys.stdout) ch.setLevel(logging.DEBUG)
fh.setFormatter(formatter) ch.setFormatter(formatter)
log.addHandler(fh) log.addHandler(ch)
return log
Пример использования:
log = get_logger('my_log') log.debug('Start')
timeout = 1000 log.info('Timeout %s', timeout)
log.warn('Not found time!') log.error('Error while requests')
log.debug('End')
Результат в консоли и в файле:
[2017-04-03 13:34:25,047] FOO_TEST_TEST.py[LINE:32] DEBUG Start [2017-04-03 13:34:25,047] FOO_TEST_TEST.py[LINE:35] INFO Timeout 1000 [2017-04-03 13:34:25,048] FOO_TEST_TEST.py[LINE:37] WARNING Not found time! [2017-04-03 13:34:25,048] FOO_TEST_TEST.py[LINE:38] ERROR Error while requests [2017-04-03 13:34:25,048] FOO_TEST_TEST.py[LINE:40] DEBUG End

Уровень логирования задается не случайно, это является фильтром, например если в get_logger подправить строку для ch и изменить уровень с DEBUG на ERROR, то в консоль попадут логи с серьезностью от ERROR и выше:
ch = logging.StreamHandler(stream=sys.stdout) ch.setLevel(logging.ERROR)
В консоли будет только:
[2017-04-03 14:04:02,742] FOO_TEST_TEST.py[LINE:40] ERROR Error while requests
В файле будет полный лог как в первом примере