Меню

Ошибка создания log файла

Ошибка создания лог-файла на сервере из обработки

Я
   Мигрень

11.06.16 — 13:07

Программно из обработки 1С создаю лог-файл. На локальном компьютере создается нормально. При переносе обработки на сервер — ошибка создания файла. Файл пытаюсь создать в папке, которая лежит на рабочем столе. Захожу на сервер через RDP. Просто вручную в этой папке могу создавать и удалять файлы без проблем. В чем может быть проблема?

   Зая Бусечка

1 — 11.06.16 — 13:08

В том, что сервер 1с работает совершенно под другим пользователем

   Мигрень

2 — 11.06.16 — 13:11

(1) Хм.. да, пожалуй. А как узнать имя пользователя, под который работает сервер 1С, чтобы попросить админа дать этому пользователю права.

   Мигрень

3 — 11.06.16 — 13:16

USR1CV81 пользователь не найден, может как-то по другому называется?

   Мигрень

4 — 11.06.16 — 13:19

USER1CV8SERVER пользователь не найден.

   hhhh

5 — 11.06.16 — 13:22

почему 81?

   PR

6 — 11.06.16 — 13:23

USR1CV8

В службах смотри

   hhhh

7 — 11.06.16 — 13:23

(4) посмотри в диспетчере задач

   Зая Бусечка

8 — 11.06.16 — 13:27

(2) Никогда не спрашивай об этом у админа!

   Мигрень

9 — 11.06.16 — 13:31

(6)(7) Точно, сейчас гляну

(8) чойта?

   Зая Бусечка

10 — 11.06.16 — 14:17

(9) А вдруг ответит? )

  

Мигрень

11 — 11.06.16 — 20:52

(10) Без админа разобрался. Попробовал создать папку не на рабочем столе, а на диске С:. Там наследование прав идет непосредственно от корня диска. Все заработало.

TurboConf — расширение возможностей Конфигуратора 1С

ВНИМАНИЕ! Если вы потеряли окно ввода сообщения, нажмите Ctrl-F5 или Ctrl-R или кнопку «Обновить» в браузере.

Тема не обновлялась длительное время, и была помечена как архивная. Добавление сообщений невозможно.
Но вы можете создать новую ветку и вам обязательно ответят!
Каждый час на Волшебном форуме бывает более 2000 человек.

За последние 24 часа нас посетили 11142 программиста и 815 роботов. Сейчас ищут 440 программистов …


  1. Stek

    С нами с:
    22 ноя 2019
    Сообщения:
    2
    Симпатии:
    0

    Добрый день, коллеги. Первый раз такая ошибка, что файл с логами не создается уже перепробовал, все что угодно. Тупо не срабатывает error_log. Что может быть?

    1. protected function logErrors($message = », $file = », $line = »){
    2.       error_log(«[» . date(‘Y-m-d H:i:s’) . «] Текст ошибки: {$message} | Файл: {$file} | Строка: {$line}n=================n», 3, ROOT . ‘/tmp/errors.log’);


  2. ADSoft

    может не в курсе внутри вашей функции что такое ROOT ?


  3. Stek

    С нами с:
    22 ноя 2019
    Сообщения:
    2
    Симпатии:
    0

    Это константа( со значением пути к главной корневой папки (типа папка «home»)


  4. freebsdd

    С нами с:
    16 апр 2019
    Сообщения:
    19
    Симпатии:
    2

    Если на юникс системах то:

    1. Доступа нет к папке
    2. Папки нет и функция даже не пытается её создать
    3. Прав нет на запись в сам лог, может даже функция пытается открыть на чтение и запись

    Да «100» причин может быть, почему конкретики то нет? Правильно заданный вопрос — уже половина ответа.

    А вообще абстрактный вопрос, и вообще Вы сказали — ОШИБКА, где ошибка то, что выдаёт при выполнении функции error_log и что значит первый раз такая ошибка, раньше было норм, после миграции стало то то?


  5. ibnteo

    ibnteo
    Активный пользователь

    С нами с:
    30 сен 2008
    Сообщения:
    15
    Симпатии:
    0

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


  6. artoodetoo

    Команда форума
    Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    10.821
    Симпатии:
    1.173
    Адрес:
    там-сям

    Дык, это говорит о том, что папка имеет атрибуты доступа, запрещающие в неё писать. Видимо папка создана одним пользователем, а вебсервер с пыхой работают под другим пользователем (www-data?). А по умолчанию доступ только на чтение.


  7. ibnteo

    ibnteo
    Активный пользователь

    С нами с:
    30 сен 2008
    Сообщения:
    15
    Симпатии:
    0

    Так в том-то и дело, что директория открыта на запись всем 0777, а файл не создаётся.


  8. artoodetoo

    Команда форума
    Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    10.821
    Симпатии:
    1.173
    Адрес:
    там-сям

    OS какая? Не замешан ли тут SELinux?
    ну или ты ошибаешся в атрибутах/ папке/ компьютере. ошибки бывают до обидного просты.


  9. ibnteo

    ibnteo
    Активный пользователь

    С нами с:
    30 сен 2008
    Сообщения:
    15
    Симпатии:
    0

    Ubuntu старая 18.04, так и не понял, кто тут виноват, PHP 7.2 или операционка, ну да ладно, хоститься всё равно будет на разных операционках.

electronicus78

1 / 1 / 0

Регистрация: 28.01.2019

Сообщений: 9

1

01.09.2019, 19:24. Показов 4430. Ответов 8

Метки нет (Все метки)


Добрый вечер. Нужна помощь, а именно — в домашнем задании необходимо создать LOG-файл, в который будет записываться элемент iTemp из блока сортировки массива. Исполняемый файл находится …SortDatabinDebugSortData.exe

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
 
namespace Вторая_фор._практ_задание_21._08._19
{
    public partial class frmSort : Form
    {
        public frmSort()
        {
            InitializeComponent();
        }
        int[] iMass = new int[100];
        private void btnLoad_Click(object sender, EventArgs e)
        {
            string sOpenFile = "";
            //создаем переменную типа string в которой будет храниться
            //путь к файлу
            OpenFileDialog.ShowDialog();
            //методом ShowDialog() вызываем диалоговое окно открытия файла
            sOpenFile = OpenFileDialog.FileName;
            //FileName возвращает строку содержащую имя файла. Если
            //пользователь выбрал файл - возвращается полный путь к файлу
            //Если пользователь нажал отмену - ничего не возвращается
            if (sOpenFile != "")
            //Проверяем, что пользователь выбрал файл, для этого строковая
            //переменная sOpenFile не должна быть пустой. Если она пустая - 
            //выводим сообщения, что файл не выбран
            {
                FileStream fsFile = new FileStream(sOpenFile, FileMode.Open);
                StreamReader fileRead = new StreamReader(fsFile);
                //создаем объекты fsFile и fileRead для чтения файла
                for (int i = 0; i < numQuantity.Value; i++)
                    iMass[i] = Convert.ToInt32(fileRead.ReadLine());
                //с помощью цикла for заполняем массив данными из файла
                //Данные из фала передаются переменными типа string
                //поэтому для записи в массив их необходимо переводить в
                //тип Int, посредством метода Convert.Toint32().
                fileRead.Close();
                //метод Close() закрывает поток чтения из файла
                lblStatus.Text = "Загрузка из файла выполнена";
                //сообщаем пользователю обуспешной загрузке файла
                btnSort.Enabled = true;
                //делаем кнопку Сортировка доступной
                btnSave.Enabled = false;
                //Делаем кнопку Сохранение недоступной. Если пользователь перед этим уже выбрал файл,
                //нажав Сортировка, а потом передумал и решил загрузить какой-либо новый файл, то, пока
                //он заново его не отсортировал, сохранение должно быть недоступно
            }
            else
                lblStatus.Text = "Файл для загрузки не выбран!";
        }
        private void btnSort_Click(object sender, EventArgs e)
        {
            if (rbtnUp.Checked == true)
            {
                for (int i = 0; i < numQuantity.Value; i++)
                    for (int j = i + 1; j < numQuantity.Value; j++)
                        if (iMass[j] < iMass[i])
                        {
                            int iTemp = iMass[i];
                            iMass[i] = iMass[j];
                            iMass[j] = iTemp;
                                               
                        }
                lblStatus.Text = "Сортировка по возрастанию выполнена";
            }
            if (rbtnDown.Checked == true)
            {
                for (int i = 0; i < numQuantity.Value; i++)
                    for (int j = i + 1; j < numQuantity.Value; j++)
                        if (iMass[j] > iMass[i])
                        {
                            int iTemp = iMass[i];
                            iMass[i] = iMass[j];
                            iMass[j] = iTemp;
                                                    }
                lblStatus.Text = "Сортировка по убыванию выполнена";
            }
            btnSave.Enabled = true; //делаем кнопку Сохранение доступной
        }
        private void btnSave_Click(object sender, EventArgs e)
        {
            if (chkSave.Checked == true)
            {
                FileStream fsFile = new FileStream("Результаты сортировки.txt", FileMode.Create);
                /*сразу выбираем название файла. Если путь не указан то файл создается в каталоге сиполняемого файла */
                StreamWriter fileWrite = new StreamWriter(fsFile);
                if (chkTitle.Checked == true)
                    fileWrite.WriteLine(txtTitle.Text);
                else
                    fileWrite.WriteLine("Отсортированный массив");
                //создаем объекты fsFile и fileWrite для записи в файл
                for (int i = 0; i < numQuantity.Value; i++)
                    fileWrite.WriteLine(Convert.ToString(iMass[i]));
                //с помощью цикла for заполняем файл данными из массива
                //конвертируя их в строковый тип
                fileWrite.Close();
                //метод Close() закрывает поток записи в файл
                lblStatus.Text = "Запись в файл выполнена";
                //сообщаем пользователю обуспешном сохранении в файл
            }
            else
                lblStatus.Text = "Файл для сохранения не выбран!";
        }
 
        private void frmSort_Load(object sender, EventArgs e)
        {
 
        }
 
        private void frmSort_FormClosing(object sender, FormClosingEventArgs e)
        {
            MessageBox.Show("Всего доброго!");
        }
 
        private void btnExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }
 
        private void chkTitle_CheckedChanged(object sender, EventArgs e)
        {
            if (chkTitle.Checked == true)
                txtTitle.Enabled = true;
            else
                txtTitle.Enabled = false;
        }
 
    }
}

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



valeriusx

2 / 1 / 1

Регистрация: 02.09.2019

Сообщений: 1

02.09.2019, 12:56

2

Лучший ответ Сообщение было отмечено electronicus78 как решение

Решение

Вот один из возможных вариантов решения на примере простой консольной аппки. Запись в сам файл выполняется за пределами цикла (количество итераций неизвестно, зачем лишний раз нагружать машину).

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
using System.IO;
using System.Text;
 
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            StringBuilder sb = new StringBuilder();
 
            // Place a specific folder you need for the log file to be placed to
            String LogFile = Environment.CurrentDirectory + "log.txt";
 
            for (int i = 0; i < 10; i++)
            {
                int iTemp = i;
 
                sb.Append(iTemp.ToString());
                sb.AppendLine();
            }
 
            // Saving the log data to file is done outside the loop
            File.Delete(LogFile);
            File.AppendAllText(LogFile, sb.ToString());
            sb.Clear();
 
        }
    }
}



1



Модератор

Эксперт .NET

13232 / 9529 / 2559

Регистрация: 21.04.2018

Сообщений: 28,127

Записей в блоге: 2

02.09.2019, 13:47

3

Цитата
Сообщение от valeriusx
Посмотреть сообщение

Вот один из возможных вариантов

ТС, насколько я понял, просил помочь встроить логирование именно в его код.
А не просто показать как записать, что в файл.



0



Элд Хасп

Модератор

Эксперт .NET

13232 / 9529 / 2559

Регистрация: 21.04.2018

Сообщений: 28,127

Записей в блоге: 2

02.09.2019, 14:45

4

Цитата
Сообщение от electronicus78
Посмотреть сообщение

в домашнем задании необходимо создать LOG-файл, в который будет записываться

Можно добавить в проект такой класс

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    public class Log
    {
        /// <summary>Имя файла логирования</summary>
        public static string FileName { get; private set; }
 
        /// <summary>Поток в файл логирования</summary>
        private static StreamWriter file;
 
        /// <summary>Задаёт файл для логирования</summary>
        /// <param name="fileName">Имя файла</param>
        /// <returns><see langword="true"/> если удачно</returns>
        public static bool SetFile(string fileName)
        {
            if (fileName == FileName)
                return false;
            StreamWriter _file;
            try
            {
                _file = File.AppendText(fileName);
            }
            catch (Exception)
            {
 
                return false;
            }
 
            Close();
            file = _file;
            FileName = fileName;
            return true;
        }
 
        /// <summary>Создаёт и подключает новый файл для логирования</summary>
        /// <param name="fileName">Имя файла</param>
        /// <returns><see langword="true"/> если удачно</returns>
        public static bool NewFile(string fileName)
        {
            if (fileName == FileName)
                return false;
            StreamWriter _file;
            try
            {
                _file = File.CreateText(fileName);
            }
            catch (Exception)
            {
 
                return false;
            }
 
            Close();
            file = _file;
            FileName = fileName;
            return true;
        }
 
        public static void Append(object message)
        {
            file.Write(Environment.NewLine + message.ToString());
            file.Flush();
        }
 
        public static void Close()
        {
            if (file != null)
            {
                file.Close();
                file.Dispose();
            }
 
            file = null;
            FileName = null;
        }
    }

Потом в проекте при запуске решения задаёте файл логирования и информацию идентифицирующую сеанс.
Допустим, можно в Program.Main

C#
1
2
3
4
5
6
7
8
9
10
    static class Program
    {
        /// <summary>
        /// Главная точка входа для приложения.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Log.SetFile("Log.txt");
            Log.Append(DateTime.Now);

И там где нужно что-то вывести в файл используете метод Log.Append.
Допустим так

C#
76
77
78
79
80
81
82
83
84
85
        for (int i = 0; i < numQuantity.Value; i++)
            for (int j = i + 1; j < numQuantity.Value; j++)
                if (iMass[j] < iMass[i])
                {
                    int iTemp = iMass[i];
                    Log.Append(iTemp);
                    iMass[i] = iMass[j];
                    iMass[j] = iTemp;
 
                }



0



1 / 1 / 0

Регистрация: 28.01.2019

Сообщений: 9

02.09.2019, 16:03

 [ТС]

5

Спасибо за помощь, буду пробовать

Добавлено через 5 минут
Элд Хасп, А немного по-проще (не добавляя в проект класс) нельзя реализовать поставленную задачу?

Добавлено через 2 минуты
А то я только учусь писать, немного сложно для меня



0



Модератор

Эксперт .NET

13232 / 9529 / 2559

Регистрация: 21.04.2018

Сообщений: 28,127

Записей в блоге: 2

02.09.2019, 21:41

6

electronicus78 -> Элд Хасп, А немного по-проще (не добавляя в проект класс) нельзя реализовать поставленную задачу?

Логирование подразумевает доступность вывода в лог из любого места приложения. Можно перенаправить консоль и выводить методами Console. Но мне кажется лучше и удобнее сделать свой класс.



0



3388 / 2406 / 1159

Регистрация: 14.08.2016

Сообщений: 8,064

02.09.2019, 22:00

7

Элд Хасп, +1, лучше сразу привыкать к правильному, ибо,например, в многопоточном приложении без класса логгера вообще не обойтись



1



1 / 1 / 0

Регистрация: 28.01.2019

Сообщений: 9

03.09.2019, 08:46

 [ТС]

8

Спасибо за помощь, продолжаю учится



0



SemaAgapova

1 / 1 / 0

Регистрация: 31.10.2020

Сообщений: 4

27.04.2021, 22:20

9

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FileStream logFile = new ("Log-файл.txt", FileMode.Create);
StreamWriter fileWrite = new(logFile);
if (rbtnUp.Checked == true)
    for (int i = 0; i < numQuantity.Value; i++)
        for (int j = i + 1; j < numQuantity.Value; j++)
           if (iMass[j] < iMass[i])
           {
               int iTemp = iMass[i];
               iMass[i] = iMass[j];
               iMass[j] = iTemp;
               fileWrite.WriteLine(Convert.ToString(iTemp));
           }
       lblStatus.Text = "сортировка по возрастанию выполнена";
       ...
       fileWrite.Close();
       ...

Для сортировки по убыванию аналогично добавлена строка fileWrite.WriteLine(Convert.ToString(iTemp));



0



MySQL logo На сервере под управлением FreeBSD 7.2-RELEASE работает mysql-server-5.0.89. Он пишет лог, согласно настройке в файле:

# less /var/db/mysql/my.cnf | grep mysql.log
log             = /var/log/mysql.log

Изначально права на этот файл лога были:

# ls -Al /var/log/ | grep mysql.log
-rw-r--r--  1 root    wheel    317542611 15 фев 13:42 mysql.log

Лог стал разрастаться (до нескольких сотен мегабайт), решил его убрать в архив, а имеющийся “обнулить”. В итоге, после рестарта сервера mysql лог не начал писаться, а в файле логов InnoDB появились записи вида:

# less /var/db/mysql/localhost.err
100215 13:55:02  mysqld started
^G/usr/local/libexec/mysqld: File '/var/log/mysql.log' not found (Errcode: 13)
100215 13:55:02 [ERROR] Could not use /var/log/mysql.log for logging (error 13). Turning logging off 
for the whole duration of the MySQL server process. To turn it on again: fix the cause, shutdown 
the MySQL server and restart it.
100215 13:55:02  InnoDB: Started; log sequence number 0 43685
100215 13:55:02 [Note] /usr/local/libexec/mysqld: ready for connections.
Version: '5.0.89-log'  socket: '/tmp/mysql.sock'  port: 3306  FreeBSD port: mysql-server-5.0.89

Пришлось заново создать файл лога работы mysql-server и дать на него следующие права:

# touch /var/log/mysql.log
# chown mysql:mysql /var/log/mysql.log
# chmod 0600 /var/log/mysql.log

Ошибки после проделанных операций этого пропали, создался лог-файл, работать с которым может только демон mysql и больше никто другой. Это очень полезно, т.к. в лог пишутся логины и пароли к базам данных.

0 Пользователей и 1 Гость просматривают эту тему.

  • 9 Ответов
  • 2815 Просмотров

Добрый день. Проблема — почему то не создаются файлы логов(папка logs) на хостинге.
Включал плагин логов, также вставлял этот код (в index.php основной)

jimport('joomla.error.log');
$log = &JLog::getInstance('my.log.php');
$log->addEntry(array('LEVEL' => '1','STATUS' => 'Username:','COMMENT' => $username));

— на локале все это работает замечательно — на хостинге файлы логов не создаются.
Права на папку — 700;
в getInstance пробовал разные расширения — log,txt,php
в configuration.php — пути до папки логов прописаны верно, проверял.

В чем может быть проблема? Заранее спасибо.

Для создания логов нужна права на папку, куда эти логи пишутся как минимум 755, а то и все 777.

Для создания логов нужна права на папку, куда эти логи пишутся как минимум 755, а то и все 777.

Сейчас поставил вообще 777. Эффект — ноль, все равно файлы не создаются.

В таком случае проверьте правильность указания пути к папке с log-файлами.
Указан должен быть полный абсолютный путь, например такой.

/home/z/zo/zorro189/somedomain.com/public_html/log/

Если полный путь вам не известен — его можно узнать в админке (Помощь — Информация о системе — Права на папки) искомый путь будет у папки cache, нужно будет его скопировать и изменить окончание пути.
Там же можно проверить и то, как воспринимает права на папки сама Joomla.

Да, конечно, это первое что я сделал —

(также путь проверял выводя $_SERVER[‘DOCUMENT_ROOT’])
в этом и есть вся странность — с папкой все ок, библиотеки error, log тоже на месте, но файлы не создаются…

Да, конечно, это первое что я сделал —

(также путь проверял выводя $_SERVER[‘DOCUMENT_ROOT’])
в этом и есть вся странность — с папкой все ок, библиотеки error, log тоже на месте, но файлы не создаются…

А почему Вы папку для логов и временных файлов делаете одну, да еще и указываете корень сайта /public_html/
Правильнее будет /public_html/logs/ и /public_html/tmp/

так попробуй сам создай файл с chmod 644,и посмотришь будет ли запись

Калатить меня в ухи))) все нормуль, проблема была в php-участке кода, сорри за невнимательность))

« Последнее редактирование: 03.04.2012, 12:02:06 от tolian_27 »

Записан

А почему Вы папку для логов и временных файлов делаете одну, да еще и указываете корень сайта /public_html/
Правильнее будет /public_html/logs/ и /public_html/tmp/

да, конечно, это я просто экспереминтировал, по всякому

Подскажите, а у меня почему-то этих записей

Log Directory ($log_path) /usr/home/тыры-пыры/logs/   Доступен на запись
Temp Directory ($tmp_path) /usr/home/тыры-пыры/tmp/   Доступен на запись

на странице «информация о системе» нет. Соответственно и нет файлов логов и временных файлов. В файле конфигурации все прописано правильно. Почему же могут не создаваться файлы? Попробовал создать файлы логов в папке вручную, через ISP менеджер. Но эти файлы так и лежат пустыми. Помогите, пожалуйста. Я из-за отсутствия файла ошибок не могу разобраться в другом баге сайта 

Сталкивались ли вы с трудностями при отладке Python-кода? Если это так — то изучение того, как наладить логирование (журналирование, logging) в Python, способно помочь вам упростить задачи, решаемые при отладке.

Если вы — новичок, то вы, наверняка, привыкли пользоваться командой print(), выводя с её помощью определённые значения в ходе работы программы, проверяя, работает ли код так, как от него ожидается. Использование print() вполне может оправдать себя при отладке маленьких Python-программ. Но, когда вы перейдёте к более крупным и сложным проектам, вам понадобится постоянный журнал, содержащий больше информации о поведении вашего кода, помогающий вам планомерно отлаживать и отслеживать ошибки.

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

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

Начало работы с Python-модулем logging

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

import logging

Встроенный модуль логирования Python даёт нам простой в использовании функционал и предусматривает пять уровней логирования. Чем выше уровень — тем серьёзнее неприятность, о которой сообщает соответствующая запись. Самый низкий уровень логирования — это debug (10), а самый высокий — это critical (50).

Дадим краткие характеристики уровней логирования:

  • Debug (10): самый низкий уровень логирования, предназначенный для отладочных сообщений, для вывода диагностической информации о приложении.

  • Info (20): этот уровень предназначен для вывода данных о фрагментах кода, работающих так, как ожидается.

  • Warning (30): этот уровень логирования предусматривает вывод предупреждений, он применяется для записи сведений о событиях, на которые программист обычно обращает внимание. Такие события вполне могут привести к проблемам при работе приложения. Если явно не задать уровень логирования — по умолчанию используется именно warning.

  • Error (40): этот уровень логирования предусматривает вывод сведений об ошибках — о том, что часть приложения работает не так как ожидается, о том, что программа не смогла правильно выполниться.

  • Critical (50): этот уровень используется для вывода сведений об очень серьёзных ошибках, наличие которых угрожает нормальному функционированию всего приложения. Если не исправить такую ошибку — это может привести к тому, что приложение прекратит работу.

В следующем фрагменте кода показано использование вышеперечисленных уровней логирования при выводе нескольких сообщений. Здесь используется синтаксическая конструкция logging.<level>(<message>).

logging.debug("A DEBUG Message")
logging.info("An INFO")
logging.warning("A WARNING")
logging.error("An ERROR")
logging.critical("A message of CRITICAL severity")

Ниже приведён результат выполнения этого кода. Как видите, сообщения, выведенные с уровнями логирования warningerror и critical, попадают в консоль. А сообщения с уровнями debug и info — не попадают.

WARNING:root:A WARNING
ERROR:root:An ERROR
CRITICAL:root:A message of CRITICAL severity

Это так из-за того, что в консоль выводятся лишь сообщения с уровнями от warning и выше. Но это можно изменить, настроив логгер и указав ему, что в консоль надо выводить сообщения, начиная с некоего, заданного вами, уровня логирования.

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

Обратите внимание на то, что в примере, который мы будем тут разбирать, весь код находится в файле main.py. Когда мы производим рефакторинг существующего кода или добавляем новые модули — мы сообщаем о том, в какой файл (имя которого построено по схеме <module-name>.py) попадает новый код. Это поможет вам воспроизвести у себя то, о чём тут идёт речь.

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

Для того чтобы настроить простую систему логирования в файл — можно воспользоваться конструктором basicConfig(). Вот как это выглядит:

logging.basicConfig(level=logging.INFO, filename="py_log.log",filemode="w")
logging.debug("A DEBUG Message")
logging.info("An INFO")
logging.warning("A WARNING")
logging.error("An ERROR")
logging.critical("A message of CRITICAL severity")

Поговорим о логгере root, рассмотрим параметры basicConfig():

  • level: это — уровень, на котором нужно начинать логирование. Если он установлен в info — это значит, что все сообщения с уровнем debug игнорируются.

  • filename: этот параметр указывает на объект обработчика файла. Тут можно указать имя файла, в который нужно осуществлять логирование.

  • filemode: это — необязательный параметр, указывающий режим, в котором предполагается работать с файлом журнала, заданным параметром filename. Установка filemode в значение w (write, запись) приводит к тому, что логи перезаписываются при каждом запуске модуля. По умолчанию параметр filemode установлен в значение a (append, присоединение), то есть — в файл будут попадать записи из всех сеансов работы программы.

После выполнения модуля main можно будет увидеть, что в текущей рабочей директории был создан файл журнала, py_log.log.

В текущей рабочей директории был создан файл журнала py_log.log

В текущей рабочей директории был создан файл журнала py_log.log

Так как мы установили уровень логирования в значение info — в файл попадут записи с уровнем info и с более высокими уровнями.

Так как уровень логирования установлен в info, в файл, помимо сообщений уровня warning, error и critical, попадут и записи уровня info

Так как уровень логирования установлен в info, в файл, помимо сообщений уровня warning, error и critical, попадут и записи уровня info

Записи в лог-файле имеют формат <logging-level>:<name-of-the-logger>:<message>. По умолчанию <name-of-the-logger>, имя логгера, установлено в root, так как мы пока не настраивали пользовательские логгеры.

В записи лог-файла закодированы уровень логирования, имя логгера и сообщение

В записи лог-файла закодированы уровень логирования, имя логгера и сообщение

Помимо базовой информации, выводимой в лог, может понадобится снабдить записи отметками времени, указывающими на момент вывода той или иной записи. Это упрощает анализ логов. Сделать это можно, воспользовавшись параметром конструктора format:

logging.basicConfig(level=logging.INFO, filename="py_log.log",filemode="w",
                    format="%(asctime)s %(levelname)s %(message)s")
logging.debug("A DEBUG Message")
logging.info("An INFO")
logging.warning("A WARNING")
logging.error("An ERROR")
logging.critical("A message of CRITICAL severity")

Благодаря настройке параметра format к записям добавлены временные метки, представленные в виде, удобном для восприятия

Благодаря настройке параметра format к записям добавлены временные метки, представленные в виде, удобном для восприятия

Существуют и многие другие атрибуты записи лога, которыми можно воспользоваться для того чтобы настроить внешний вид сообщений в лог-файле. Настраивая поведение логгера root — так, как это показано выше, проследите за тем, чтобы конструктор logging.basicConfig()вызывался бы лишь один раз. Обычно это делается в начале программы, до использования команд логирования. Последующие вызовы конструктора ничего не изменят — если только не установить параметр force в значение True.

Логирование значений переменных и исключений

Модифицируем файл main.py. Скажем — тут будут две переменных — x и y, и нам нужно вычислить значение выражения x/y. Мы знаем о том, что при y=0 мы столкнёмся с ошибкой ZeroDivisionError. Обработать эту ошибку можно в виде исключения с использованием блока try/except.

Далее — нужно залогировать исключение вместе с данными трассировки стека. Чтобы это сделать — можно воспользоваться logging.error(message, exc_info=True). Запустите следующий код и посмотрите на то, как в файл попадают записи с уровнем логирования info, указывающие на то, что код работает так, как ожидается.

x = 3
y = 4

logging.info(f"The values of x and y are {x} and {y}.")
try:
    x/y
    logging.info(f"x/y successful with result: {x/y}.")
except ZeroDivisionError as err:
    logging.error("ZeroDivisionError",exc_info=True)

В файл журнала попали записи с уровнем логирования info

В файл журнала попали записи с уровнем логирования info

Теперь установите значение y в 0 и снова запустите модуль.

Исследуя лог-файл py_log.log, вы увидите, что сведения об исключении были записаны в него вместе со стек-трейсом.

x = 4
y = 0

logging.info(f"The values of x and y are {x} and {y}.")
try:
    x/y
    logging.info(f"x/y successful with result: {x/y}.")
except ZeroDivisionError as err:
    logging.error("ZeroDivisionError",exc_info=True)

В журнале появилась запись об ошибке вместе с результатами трассировки стека

В журнале появилась запись об ошибке вместе с результатами трассировки стека

Теперь модифицируем код так, чтобы в нём имелись бы списки значений x и y, для которых нужно вычислить коэффициенты x/y. Для логирования исключений ещё можно воспользоваться конструкцией logging.exception(<message>).

x_vals = [2,3,6,4,10]
y_vals = [5,7,12,0,1]

for x_val,y_val in zip(x_vals,y_vals):
    x,y = x_val,y_val
    logging.info(f"The values of x and y are {x} and {y}.")
    try:
        x/y
        logging.info(f"x/y successful with result: {x/y}.")
    except ZeroDivisionError as err:
        logging.exception("ZeroDivisionError")

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

Записи об успешных попытках вычисления коэффициента и об исключении

Записи об успешных попытках вычисления коэффициента и об исключении

Настройка логирования с помощью пользовательских логгеров, обработчиков и форматировщиков

Отрефакторим код, который у нас уже есть. Объявим функцию test_division.

def test_division(x,y):
    try:
        x/y
        logger2.info(f"x/y successful with result: {x/y}.")
    except ZeroDivisionError as err:
        logger2.exception("ZeroDivisionError")

Объявление этой функции находится в модуле test_div. В модуле main будут лишь вызовы функций. Настроим пользовательские логгеры в модулях main и test_div, проиллюстрировав это примерами кода.

Настройка пользовательского логгера для модуля test_div

import logging

logger2 = logging.getLogger(__name__)
logger2.setLevel(logging.INFO)

# настройка обработчика и форматировщика для logger2
handler2 = logging.FileHandler(f"{__name__}.log", mode='w')
formatter2 = logging.Formatter("%(name)s %(asctime)s %(levelname)s %(message)s")

# добавление форматировщика к обработчику
handler2.setFormatter(formatter2)
# добавление обработчика к логгеру
logger2.addHandler(handler2)

logger2.info(f"Testing the custom logger for module {__name__}...")

def test_division(x,y):
    try:
        x/y
        logger2.info(f"x/y successful with result: {x/y}.")
    except ZeroDivisionError as err:
        logger2.exception("ZeroDivisionError")

Настройка пользовательского логгера для модуля main

import logging
from test_div import test_division 

# получение пользовательского логгера и установка уровня логирования
py_logger = logging.getLogger(__name__)
py_logger.setLevel(logging.INFO)

# настройка обработчика и форматировщика в соответствии с нашими нуждами
py_handler = logging.FileHandler(f"{__name__}.log", mode='w')
py_formatter = logging.Formatter("%(name)s %(asctime)s %(levelname)s %(message)s")

# добавление форматировщика к обработчику 
py_handler.setFormatter(py_formatter)
# добавление обработчика к логгеру
py_logger.addHandler(py_handler)

py_logger.info(f"Testing the custom logger for module {__name__}...")

x_vals = [2,3,6,4,10]
y_vals = [5,7,12,0,1]

for x_val,y_val in zip(x_vals,y_vals):
    x,y = x_val, y_val
    # вызов test_division
    test_division(x,y)
    py_logger.info(f"Call test_division with args {x} and {y}")

Разберёмся с тем, что происходит коде, где настраиваются пользовательские логгеры.

Сначала мы получаем логгер и задаём уровень логирования. Команда logging.getLogger(name) возвращает логгер с заданным именем в том случае, если он существует. В противном случае она создаёт логгер с заданным именем. На практике имя логгера устанавливают с использованием специальной переменной name, которая соответствует имени модуля. Мы назначаем объект логгера переменной. Затем мы, используя команду logging.setLevel(level), устанавливаем нужный нам уровень логирования.

Далее мы настраиваем обработчик. Так как мы хотим записывать сведения о событиях в файл, мы пользуемся FileHandler. Конструкция logging.FileHandler(filename) возвращает объект обработчика файла. Помимо имени лог-файла, можно, что необязательно, задать режим работы с этим файлом. В данном примере режим (mode) установлен в значение write. Есть и другие обработчики, например — StreamHandler, HTTPHandler, SMTPHandler.

Затем мы создаём объект форматировщика, используя конструкцию logging.Formatter(format). В этом примере мы помещаем имя логгера (строку) в начале форматной строки, а потом идёт то, чем мы уже пользовались ранее при оформлении сообщений.

Потом мы добавляем форматировщик к обработчику, пользуясь конструкцией вида <handler>.setFormatter(<formatter>). А в итоге добавляем обработчик к объекту логгера, пользуясь конструкцией <logger>.addHandler(<handler>).

Теперь можно запустить модуль main и исследовать сгенерированные лог-файлы.

Лог-файл main.log

Лог-файл main.log
Лог-файл test_div.log
Лог-файл test_div.log

Рекомендации по организации логирования в Python

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

  • Устанавливайте оптимальный уровень логирования. Логи полезны лишь тогда, когда их можно использовать для отслеживания важных ошибок, которые нужно исправлять. Подберите такой уровень логирования, который соответствует специфике конкретного приложения. Вывод в лог сообщений о слишком большом количестве событий может быть, с точки зрения отладки, не самой удачной стратегией. Дело в том, что при таком подходе возникнут сложности с фильтрацией логов при поиске ошибок, которым нужно немедленно уделить внимание.

  • Конфигурируйте логгеры на уровне модуля. Когда вы работаете над приложением, состоящим из множества модулей — вам стоит задуматься о том, чтобы настроить свой логгер для каждого модуля. Установка имени логгера в name помогает идентифицировать модуль приложения, в котором имеются проблемы, нуждающиеся в решении.

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

  • Применяйте ротацию лог-файлов ради упрощения отладки. При работе над большим приложением, в состав которого входит несколько модулей, вы, вполне вероятно, столкнётесь с тем, что размер ваших лог-файлов окажется очень большим. Очень длинные логи сложно просматривать в поисках ошибок. Поэтому стоит подумать о ротации лог-файлов. Сделать это можно, воспользовавшись обработчиком RotatingFileHandler, применив конструкцию, которая строится по следующей схеме: logging.handlers.RotatingFileHandler(filename, maxBytes, backupCount). Когда размер текущего лог-файла достигнет размера maxBytes, следующие записи будут попадать в другие файлы, количество которых зависит от значения параметра backupCount. Если установить этот параметр в значение K — у вас будет K файлов журнала.

Сильные и слабые стороны логирования

Теперь, когда мы разобрались с основами логирования в Python, поговорим о сильных и слабых сторонах этого механизма.

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

Кроме того, исследование логов ошибок — это сложно, особенно в том случае, если сообщения об ошибках не содержат достаточных сведений о контекстах, в которых происходят ошибки. Когда выполняют команду logging.error(message), не устанавливая при этом exc_info в True, сложно обнаружить и исследовать первопричину ошибки в том случае, если сообщение об ошибке не слишком информативно.

В то время как логирование даёт диагностическую информацию, сообщает о том, что в приложении нужно исправить, инструменты для мониторинга приложений, вроде Sentry, могут предоставить более детальную информацию, которая способна помочь в диагностике приложения и в исправлении проблем с производительностью.

В следующем разделе мы поговорим о том, как интегрировать в Python-проект поддержку Sentry, что позволит упростить процесс отладки кода.

Интеграция Sentry в Python-проект

Установить Sentry Python SDK можно, воспользовавшись менеджером пакетов pip.

pip install sentry-sdk

После установки SDK для настройки мониторинга приложения нужно воспользоваться таким кодом:

sentry_sdk.init(
     dsn="<your-dsn-key-here>",
     traces_sample_rate=0.85,
)

Как можно видеть — вам, для настройки мониторинга, понадобится ключ dsn. DSN расшифровывается как Data Source Name (имя источника данных). Найти этот ключ можно, перейдя в Your-Project > Settings > Client Keys (DSN).

После того, как вы запустите Python-приложение, вы можете перейти на Sentry.io и открыть панель управления проекта. Там должны быть сведения о залогированных ошибках и о других проблемах приложения. В нашем примере можно видеть сообщение об исключении, соответствующем ошибке ZeroDivisionError.

Логи в интерфейсе Sentry.io

Логи в интерфейсе Sentry.io

Изучая подробности об ошибке, вы можете увидеть, что Sentry предоставляет подробную информацию о том, где именно произошла ошибка, а так же — об аргументах x и y, работа с которыми привела к появлению исключения.

Подробные сведения об исключении

Подробные сведения об исключении

Продолжая изучение логов, можно увидеть, помимо записей уровня error, записи уровня info. Налаживая мониторинг приложения с использованием Sentry, нужно учитывать, что эта платформа интегрирована с модулем logging. Вспомните — в нашем экспериментальном проекте уровень логирования был установлен в значение info. В результате Sentry записывает все события, уровень которых соответствует info и более высоким уровням, делая это в стиле «навигационной цепочки», что упрощает отслеживание ошибок.

Sentry позволяет фильтровать записи по уровням логирования, таким, как info и error. Это удобнее, чем просмотр больших лог-файлов в поиске потенциальных ошибок и сопутствующих сведений. Это позволяет назначать решению проблем приоритеты, зависящие от серьёзности этих проблем, и, кроме того, позволяет, используя навигационные цепочки, находить источники неполадок.

Фильтрация записей по уровням логирования

Фильтрация записей по уровням логирования

В данном примере мы рассматриваем ZeroDivisionError как исключение. В более крупных проектах, даже если мы не реализуем подобный механизм обработки исключений, Sentry автоматически предоставит диагностическую информацию о наличии необработанных исключений. С помощью Sentry, кроме того, можно анализировать проблемы с производительностью кода.

Сведения о проекте

Сведения о проекте

Код, использованный в данном руководстве, можно найти в этом GitHub-репозитории.

Итоги

Освоив это руководство, вы узнали о том, как настраивать логирование с использованием стандартного Python-модуля logging. Вы освоили основы настройки логгера root и пользовательских логгеров, ознакомились с рекомендациями по логированию. Вы, кроме того, узнали о том, как платформа Sentry может помочь вам в деле мониторинга ваших приложений, обеспечивая вас сведениями о проблемах с производительностью и о других ошибках, и используя при этом все возможности модуля logging.

Когда вы будете работать над своим следующим Python-проектом — не забудьте реализовать в нём механизмы логирования. И можете испытать бесплатную пробную версию Sentry.

О, а приходите к нам работать? 🤗 💰

Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.

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

Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.

Присоединяйтесь к нашей команде.

First of all, I tried every solution that exist, but nothing is working, so I don’t want from anyone to say this question is duplicated.

I cannot log to the file using logback, but I can log to console without problems.

My logback.xml file content:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
                  ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
    </encoder>
  </appender>

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!--See http://logback.qos.ch/manual/appenders.html#RollingFileAppender-->
    <!--and http://logback.qos.ch/manual/appenders.html#TimeBasedRollingPolicy-->
    <!--for further documentation-->
    <append>true</append>
    <File>/root/connector/logs/connector.log</File>
    <encoder>
        <!-- was: %d{yyyy-MM-dd HH:mm:ss}%5p [%t] (%F:%L) - %msg%n -->
      <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] (%class{25}:%line) - %msg%n</pattern>
    </encoder>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- By setting the name to .gz here, we get free compression. -->
      <fileNamePattern>/root/connector/logs/connector.log.%d{yyyy-MM-dd}.gz</fileNamePattern>
    </rollingPolicy>
  </appender>

  <root level="DEBUG">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE" />
  </root>
</configuration>

I even tried to give all users the permission to write in the folder, but this doesn’t work.

drwxrwxrwx. 2 nobody nobody 4096 Apr 29 08:24 logs

I repeat again, I tried every solution that exists, but nothing is working.

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Ошибка создания персонажа вов
  • Ошибка создания файла носитель защищен от записи