Лог программы что это

Профессиональный подход к ведению логов

Логи можно сравнить с уликами на месте преступления, а разработчиков — с криминалистами. Роль логов трудно переоценить, ведь когда необходимо найти баг или причину сбоя, сразу обращаются к ним. Подобно тому, как отсутствие улик приводит к нераскрытым делам, отсутствие содержательных логов осложняет диагностику и устранение ошибок, превращая их в затянувшийся или вовсе невыполнимый процесс. Мне приходилось наблюдать, как люди мучились с такими инструментами, как Strace и tcpdump, или развертывали новый код в продакшене во время сбоя лишь затем, чтобы получить больше лог-файлов для выявления проблемы.

Как говорится: “Хорошо подготовиться — половину дела сделать”, так что каждому профессиональному разработчику следует научиться эффективно вести логи и быть готовым к работе с ними. В данной статье мы не только рассмотрим список полезных практик логирования в приложении, но и разберем теоретические основы данного процесса: что записываем, когда и кто этим должен заниматься.

Что такое Логи и зачем они нужны

Как осуществляется процесс отладки?

Прежде чем начать разговор о логах, необходимо ответить на два вопроса:

  1. Что такое программа?
  2. Как осуществляется отладка, в которой логи играют важную роль?

Программа как переходы состояний

Программа — это серия переходов между состояниями.

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

Допустим, есть робот, задача которого — заполнить бензобак машины. Если мы рассмотрим выполняемые им действия как переходы состояний, то ему необходимо перейти от состояния (бак пустой, в наличии 50 $) к состоянию (бак полный, в наличии 15 $). Если же мы описываем его как процесс, то он должен найти заправку, доставить туда машину и заплатить. Конечно же, процесс имеет большое значение, но состояния дают более точную оценку правильности программы.

Отладка

Отладка — это мысленная реконструкция переходов состояний. Разработчики проигрывают в уме сценарий программы: как она принимает вводные данные, проходит через ряд изменений состояний и осуществляет вывод, а затем определяют, что пошло не так. Во время разработки этот мыслительный процесс подкрепляется использованием отладчика. Однако в продакшене делать это уже гораздо сложнее, поэтому на данном этапе чаще прибегают к помощи логов.

Что записывать в лог ?

Понимая суть процесса отладки, мы с легкостью ответим на этот вопрос:

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

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

Что такое лог (log) программы

Переход в критическое состояние

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

Предположим, что существуют 3 фазы запуска приложения:

  • загрузка настроек программы;
  • подключение к зависимостям;
  • запуск сервера.

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

Ключевые характеристики

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

Например, когда HTTP-сервер переходит из состояния ожидания запроса в состояние получения запроса, он должен зафиксировать в логе HTTP-метод и URL, так как они описывают основы HTTP-запроса. Остальные его элементы (заголовки или часть тела сообщения) записываются в том случае, если их значения влияют на бизнес-логику. Например, если поведение сервера сильно отличается между состояниями Content-Type:application/json и Content-Type:multipart/form-data, заголовок следует записать.

Причина перехода состояния

Пример

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

Вот несколько анти-шаблонов логов, в которых отсутствуют ключевые характеристики состояния и причины:

  • [2020–04–20T03:36:57+00:00] server.go: Error processing request (Запрос на обработку ошибок)
  • [2020–04–20T03:36:57+00:00] server.go: SSN rejected (Номер социального страхования отклонен)
  • [2020–04–20T03:36:57+00:00] server.go: SSN rejected for user UUID “123e4567-e89b-12d3-a456–426655440000” (Номер социального страхования отклонен для пользователя UUID “123e4567-e89b-12d3-a456–426655440000”)

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

[2020–04–20T03:36:57+00:00] server.go: Received a SSN request(track id: “e4a49a27–1063–4ab3–9075-cf5faec22a16”) from user uuid “123e4567-e89b-12d3-a456–426655440000”(previous state), rejecting it(next state) because the server is expecting SSN format AAA-GG-SSSS but got **-***(why)

([2020–04–20T03:36:57+00:00] server.go: Получен запрос номера социального страхования (трек id: “e4a49a27–1063–4ab3–9075-cf5faec22a16”) от пользователя user uuid “123e4567-e89b-12d3-a456–426655440000” (предыдущее состояние), запрос отклонен (следующее состояние), так как сервер требует номер социального страхования в формате AAA-GG-SSSS, а получил **-*** (причина)

Читайте также:
Федеральная программа защиты заемщиков что это

Кто должен записывать логи?

Типичная ошибка, которую многие допускают, связана с тем, “кто” должен фиксировать информацию. Ведение логов не теми функциями оборачивается дублированием или дефицитом информации.

Программа как уровни абстракции

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

Например, веб-сайт может состоять из следующих уровней: бизнес-логика, HTTP и TCP/IP. Реагируя на URL-запрос, уровень бизнес-логики решает, какую веб-страницу показать, и отправляет ее контент на уровень HTTP, где он превращается в HTTP-ответ. Следующий уровень TCP/IP преобразует HTTP-ответ в пакеты TCP и рассылает их.

Ведите логи только на правильных уровнях

Как следствие абстракции, разные уровни имеют разные степени понимания выполняемой задачи. В предыдущем примере уровень HTTP не владел данными ни о количестве отправляемых пакетов TCP, ни о намерении пользователей в момент URL-запроса. Предпринимая попытку логирования, разработчикам следует выбрать правильный уровень, который содержит полную информацию о переходах состояний и причинах.

Вернемся к нашему примеру проверки корректности номера социального страхования. Допустим, что логика его проверки обернута в класс Validator следующим образом:

public class Validator // другие функции проверки.

public static void validateSSN(String ssn) throws ValidationException // выполнение проверки
String regex = «^(?!000|666)[0-8][0-9]-(?!00)[0-9]-?!0000)[0-9]$»;
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(ssn);

if (!matcher.matches()) // —> Записываем в лог местоположение A
logger.info(«Bad SSN blah, blah, blah. «);
throw new ValidationException(String.format(«expecting SSN format AAA-GG-SSSS but got %s», ssn.replaceAll(«\d», «*»)));
>
>
>

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

public class Validator // другие функции проверки.

public static void validateUserUpdateRequest(UserUpdateRequestreq) // проверка другого атрибута req .

try validateSSN(req.ssn);
> catch (ValidationException e) // —> Записываем в лог местоположение B
logger.info(String.format(«Received a user update request(track id %s) from user uuid %s, rejecting it because %s», req.trackID, req.uid, e.getMessage()));
// другая логика обработки ошибки .
>

// остальная логика.
>
>

Существует два местоположения (A и B) для записи логов об ошибке проверки номера социального страхования, но только B владеет достаточной для этого информацией . В A программа не знает, ни какой запрос она обрабатывает, ни от какого пользователя он поступает. Логирование просто добавляет деталей. Будет лучше, если validateUserUpdateRequest выбросит ошибку из вызывающего компонента (validateRequest), содержащего больше контекста для лога.

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

Сколько должно быть логов?

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

Установите соотношение между логами и рабочей нагрузкой

Для контроля объема логов сначала важно его правильно измерить. Большинство программ имеют 2 типа рабочей нагрузки:

  • получение рабочих элементов (запросов) и последующая реакция на них;
  • запрос рабочих элементов откуда-либо и последующее выполнение действий.

В большинстве случаев процесс логирования запускается рабочей нагрузкой: чем больше ее у программы, тем больше логов она записывает. Могут быть и другие логи, не связанные с рабочей нагрузкой, но они становятся малозначимыми, когда программа начинает работу. Разработчики должны сохранять соотношение # логов и # рабочих элементов линейным. Иначе говоря:

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

  • 0 < X < 1. Это значит, что логи отбираются выборочно, и не у всех рабочих элементов они есть, например ведётся запись только ошибок или используются другие алгоритмы отбора логов. Это способствует снижению объемов лога, но при этом может ограничить возможности поиска проблемы.
  • X ~ 1. Это значит, что в среднем каждый рабочий элемент производит примерно одну запись. И это целесообразно до тех пор, пока один лог содержит достаточно информации (подробно в разделе “Что записывать в лог?”).
  • X >> 1. У разработчиков должна быть весомая причина для того, чтобы X был существенно больше, чем 1. Когда рабочая нагрузка возрастает, например в случае с сервером, на который обрушивается внезапный шквал HTTP-запросов, то X лишь усиливает ее и чрезмерно нагружает инфраструктуру логирования, что обычно вызывает проблемы.

Используйте уровни логов

Что, если X все еще слишком большой даже после оптимизации? На помощь приходят уровни логов. Если X намного больше, чем 1, то можно поместить логи на уровень DEBUG, тем самым снизив X уровня INFO. В процессе устранения неполадок программа может временно выполняться на этом уровне для предоставления дополнительной информации.

Краткие выводы

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

1.Когда писать логи? В момент перехода в критическое состояние.

2.Что записывать в лог? Ключевые характеристики текущего состояния и причину перехода состояния.

3.Кто должен записывать логи? Логирование должно происходить на правильном уровне, содержащем достаточно информации.

4.Каким должно быть количество логов? Определите X-фактор (по формуле # логов = X * # рабочих элементов+ константы) и настройте его экономно, но выгодно.

  • Логирование в Python с помощью Logzero
  • Используйте перечисления, а не логические аргументы
  • Логи в Python. Настройка и централизация

Источник: medium.com

Что такое лог (log) программы.

Решая различные компьютерные задачи, можно не раз столкнуться с таким понятием как лог (с англ. log). Лог какой-то программы. Давайте попробуем разобраться что это такое и для чего это нужно.

Читайте также:
Что за программа avid

Log (с англ. журнал). У большинства программ, которые установлены на вашем компьютере, есть этот самый журнал.

Журнал — это специальный текстовый файл, в который программа может вносить какие-то записи.

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

Зачем же программе вести какие-то записи, какой-то журнал?

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

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

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

Лог файлов для программы может быть несколько. В зависимости от назначения может быть так называемый access_log — это журнал, где фиксируются все взаимодействия пользователей с этой программой, что они делали и.т.д.

В лог файле может множество записей. Каждая текстовая строка — это одно взаимодействие с программой.

В каждой записи содержится информация о том, что происходило с программой и когда это происходило.

Также можно часто встретить так называемый error_log — это лог тех ошибок, которые возникали при работе с программой. В этом логе можно увидеть код ошибки, которая произошла в программе, когда эта ошибка произошла, каким пользователем операционной системы эта ошибка была вызвана и.т.д.

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

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

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

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

Источник: webkyrs.info

Логирование Java: терминология, уровни логирования, log-файлы

Lorem ipsum dolor

Напишем

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

Иногда с вашим программным продуктом происходит что-то непонятное , и он начинает себя вести не так , как задумано.

Первое , что приходит на ум в этом случае , — в программе есть наличие ошибок. Самый п р остой способ это проверить — использовать логи программы, так как это возможность посмотреть, что происходит «внутри» самой программы.

Логирование Java напоминает процесс работы «черного ящика» в самолете — в случае возникновения критических ситуаций оно способно «рассказать», что не так работает и на что обратить внимание.

Термин «лог» — что это такое?

Напишем

Логирование — это процесс, который неразрывно связан с термином «лог». Лог с английского можно перевести как «бортовой журнал».

В программировании лог — это специальный файл, который выполняет функцию «бортового журнала» программы. Именно в этот файл, а точнее , в лог программа производит записи о своей работе. Лог-файлы программа может создавать самостоятельно, чтобы вносить туда текстовые пометки.

Лог-файлы помогают «следить» за действиями программы, например, что она функционирует в конкретный момент времени или как она реагирует на действия пользователя.

У одного программного продукта лог-файлы могут быть разные. Например , может быть лог — файл типа:

  • «access_log», в котором фиксируются действия программы при ее взаимодействии с пользователями;
  • «error_log», в котором фиксируются все ошибки, произош едшие в результате работы программы;
  • и др.

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

Отметим различия между «логированием» и «логом»:

  • логирование — это процесс, при котором программа прописывает какие-то записи в лог-файлы;
  • лог — это сам файл или то место , куда программа производит необходимые записи.

Уровни логирования

Напишем

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

Уровни логирования применяются в программах на различных языках программирования, в том числе и на Java. Различают несколько основных уровней:

  • debug — выводится информация, которая пригодится для отладки программы;
  • info — обычные и стандартные сообщения;
  • warning — нефатальное предупреждение;
  • error — записи ошибок;
  • fatal — фатальная ошибка;
  • off — сообщения не выводятся;
  • trace — информация для точной отладки;
  • all — выводится вся информация.

«Поддержать» уровни логирования в Java можно двумя способами:

  1. Внутри программы можно расставить вызов нужной библиотеки в соответствии с заданным уровнем. Например, если произойдет ошибка, она будет логироваться как «error» и т. д.
  2. В момент запуска программы нужно указать уровень логирования для конкретной ситуации. Если ничего не указывать, то для программы будет применяться уровень «info», где буд у т записываться все ключевые и важные события, происходящие с программой, в том числе «warning» и «error». Если указать «error», будут записываться только ошибки.
Читайте также:
Компас 3d что это за программа особенности

Логирование Java: термины

Напишем

Библиотеки логирования Java включают в себя 3 основных термина:

  1. Logger — это некий объект, который отвечает за запись информации в лог-файлы, опираясь на заданные уровни логирования. Основная задача логгера — не пропустить событие, которое нужно записать в лог-файл.
  2. Appender — это конечная точка, куда «приходит» информация для логирования. В качестве appender мо гут выступать: файл, база данных, консоль, сокет и др. У appender нет каких-либо ограничений, куда записывать сообщения. Все ограничивается только вашими способностями. Если Logger — это начальная точка в логировании, то Appender — это конечная точка. При этом один «логгер» может содержать несколько «аппендеров» и наоборот.
  3. Layout — это формат, в котором выводятся сообщения. Форматирование сообщений напрямую зависит от используемой библиотеки при логировании.

Библиотеки логирования Java

Напишем

Библиотеки логирования Java — это набор инструментов, который применяют при логировании программ. Различают несколько популярных инструментов логирования:

  1. Apache log4j. Это первый набор инструментов для логирования Java, который появился еще в 1999-м году. Внутри себя имеет различны е способы вывода логов, несколько форматов логирования и мн. др. Раньше данная библиотека активно применялась, но уже долгое время этот проект не развивается.
  2. JUL. Имеет множество уровней логирования, например , только для отладки у этого инструмента есть в арсенале 3 отладочных уровня вместо одного стандартного.
  3. SLF4J. Этот инструмент является оберткой над многими популярными логгерами, например: logback, log4j, jul и др., поэтому его рекомендуется использовать в паре с полноценной библиотекой для логирования.
  4. Logback был создан как альтернатива умирающему log4j, поэтому он вобрал в себя все лучшее из этого инструмента, при этом усовершенствовал некоторые показатели.

Заключение

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

Мы будем очень благодарны

если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.

Источник: codernet.ru

Что такое лог файл?

Что такое лог файл?

В рамках данной заметки, я расскажу вам что такое лог файл и зачем он нужен.

Представьте, что вы поехали на природу и случилось так, что никто не взял с собой ни единого шампура для шашлыков. Что вы будете делать в такой ситуации, кроме рациональных вещей вида «используем веточки»? Скорее всего, будете выяснить причины почему так вышло. А теперь, представьте, что вы еще только собираетесь в поездку. Что будете делать?

Скорее всего, уточнять предпочтения в еде и напитках.

Все это можно так же отнести и к программам (сайтам, сервисам и прочему). Если возникают проблемы или же необходимость проанализировать активность пользователей, то нужен какой-то источник данных. Только вот, в отличии от людей, вы не можете просто так спросить программу. Поэтому программы используют лог файлы.

Но, обо всем по порядку.

Лог файл это

Что такое лог файл?

Лог файл — это файл, в котором хранятся в хронологическом порядке записи о событиях. Например, первая запись — «1-го числа был добавлен пользователь Х», вторая запись — «2-го числа произошла ошибка при попытке открыть картинку» и так далее. В некотором роде, это как дневник.

Какие события записываются в лог файлы?

1. Внешние. Это действия пользователей или иных программ (например, если один сайт запрашивает данные у другого). Так, например, в лог файлах веб-серверов обычно записываются какие страницы пытался открыть пользователь, какой у него IP-адрес, какие файлы скачивал и тому подобное.

2. Внутренние. Это действия самой программы. Ошибки, выполненные тесты, замеры скорости, промежуточные результаты для отладки и так далее.

Какие особенности чаще всего связаны с лог файлами? Одна из основных проблем журналирования действий — это объем данных. При чем подразумевает эта проблема два аспекта. Во-первых, количество записей. Их могут быть сотни, тысяч, десятки тысяч и даже миллионы.

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

Поэтому нередко бывает так, что программа ведет ни один лог файл, а множество. Например, это могут быть отдельные файлы, в каждом из которых хранятся записи только за определенный период (например, день или месяц), это может быть несколько файлов, переключаемых по мере достижения определенного объема (например, три файла и каждый размером не более 1 Мб, заполнился первый — заполняется второй — заполнился второй — заполняется третий — заполнился третий — заново заполняется первый — и так далее). Порой, встречаются и более сложные вариации ведения лог файлов. Например, журналирование по определенным фильтрам: в один файл сохраняются данные о загрузках файлов пользователем Х1 за период Х2, во второй ошибки программы, связанные только с определенными функциями, и так далее.

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

В каком виде обычно хранятся лог файлы? Так как наиболее частая задача таких файлов это быстро решать проблемы, то поэтому так же часто это простые текстовые файлы, которые можно открыть любым текстовым редактором (например, Notepad++ или стандартный блокнот Windows), даже если у них своеобразные расширения, такие как «log» (logs), «err» и прочие. Однако, бывают вариации. Например, информация может быть записана в собственном формате, который без специальных программ не посмотреть.

Теперь, вы знаете что такое лог файл, а так же некоторые особенности.

☕ Понравился обзор? Поделитесь с друзьями!

Источник: ida-freewares.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru