LINUX.ORG.RU

Сообщения DRVTiny

 

Быть может, мы уже уходим?

В современном мире не развивается только один интеллект: человеческий.

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

Вопрос же не об AI, а о человеке.

Мы-то развиваемся? Становятся люди умнее, сильнее или вообще хоть в чём-то эффективнее от поколения к поколению?

А если нет, то каковы наши реальные перспективы? И для чего вообще нужен технический прогресс? Для «счастья человечества», для удовлетворения потребностей «лучших из лучших» или просто сам по себе выполняет слепую и в действительности неконтролируемую эволюционную функцию?

 humanity,

DRVTiny
()

Платность ZenOSS

Товарищи!

Правильно ли я понимаю, что к ZenOSS, у которой есть ведь OpenSource-кусок, тем не менее коммунистические идеалы и ценности неприменимы, ибо уже после 1000 устройств эта штука резко становится платной?

P.S. Поискал хоть какие-нибудь форки ZenOSS - никто не делал. Наверное, лицензия не позволяет... её я не читал :)

 

DRVTiny
()

Стекирование обработчиков сигналов

Какова правильная идеология обработки сигналов?

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

Просто я смотрю на чужой perl'овый код - и вижу, как там $SIG{'HUP'}=sub {} - и мне плакать хочется. И это далеко не только в каких-то примитивных приложениях, в достаточно серьёзных тоже. Особенно напрягает то, что я-то могу сигналы правильно обрабатывать и честно пушить в $sigHndl{'HUP'} обработчики HUP'а. Но в один непрекрасный момент я могу не заметить, как некий чужой модуль возьмёт и сделает $SIG{'HUP'}=... Да, после этого я найду email чувака и насру ему в почту тонну говна, и не успокоюсь, пока не пойму, что чувак понял, насколько он идиот. Но.. Хотелось бы себя обезопасить как-то от таких вещей.

Поэтому номер раз:

Правильно ли я понимаю, что можно запретить модификацию %SIG'а или как-то иначе заблокировать назначение новых обработчиков?

А ещё все мы знаем, что чудес не бывает, хоть они изредка и мироточат, но в целом к чудесам мы относимся с некоторой настороженностью. Так и с обработчиками сигналов: весьма похоже на то, что обработчик сигнала в лучшем случае может быть прерван другим обработчиком (на самом деле нет). А это, в случае использования идеологии «запихни мне обработчиков в стек» - may lead to навсегда зависшее в самом неожиданном месте приложение. Ну, оно же просто обрабатывало... Соответственно,

Номер два:

А верно ли я мыслю, то обработчики сигнала после срабатывания такового сигнала должны:

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

2) Реальный код каждого обработчика из стека должен тем или иным способом заворачиваться в «блок, который не может выполняться дольше $nTimeout микросекунд» - это ж, небось, про SIG{ALRM}...

Иначе - ну хорошо конечно, когда всё хорошо, но если уж плохо - то совсем плохо, ибо всё стоит колом и никуда не едет.

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

Всем заблаговременной гигантской признательности!

P.S. Я слышал про AnyEvent и даже Mojolicious пользуюсь активно. Вопрос в том, что обработчики сигнала там назначаются по принципу «1 сигнал - 1 обработчик». Соответственно, если в действительности в общем случае нужно ~100500 обработчиков, то их нужно вызывать из того одного обработчика, а в этом-то и загвоздка: что именно должен делать он для более-менее гарантированно стабильной работы приложения?

 , , ,

DRVTiny
()

require: как понять, что за пакет был подключен?

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

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

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

2) Подключать плагины по имени файла без расширения *.pm - и тогда нужно будет как-то понять, что за пакет-то был подключен в итоге, но не парсить же на предмет /^\s*package\s+(\w+)/ ради этого!

Есть ли что-то уже готовое для 1 или 2?

В PHP такие штуки не особо проблемно делаются автозагрузчиками модулей/классов. Для Perl'а что-то в упор не нашёл. Плохо искал?

 

DRVTiny
()

Ruby в качестве замены Perl

Давненько уже подумываю активно писать на чём-либо, помимо Perl'а.

Синтаксис наиболее популярного у хомячков Python'а вызывает у меня откровенное отвращение, язык Julia, который вроде и нравится, в качестве языка общего назначения пока откровенно слаб, да и его нестабильность несколько напрягает. Языки C#, D, Java - многословны и сложны для тех достаточно простых приложений и библиотек, которые я пишу (к тому же наиболее мне симпатичный здесь язык C# - по сути мало популярен на *nix'ах, поскольку ему нужен mono).

Посмотрел на Ruby - вроде неплохо. Есть конечно косяки в виде «@@» (очень странное изобретение - обозначать префиксом область видимости переменной) и прочих чудесных вещей наподобие end'ов и def'ов (что за идиотская обфускация, для чего?), но в целом явно лучше Python'а, вполне удобный синтаксис.

Несколько напрягает тот факт, что популярность Ruby явно обусловлена убывающей, насколько я знаю, популярностью Ruby-On-Rails и в целом, в отличие от того же Perl'а и Python'а, Ruby в качестве языка на все случаи жизни якобы мало используется - сфера применения у него ограничена веб-технологиями (опять же, не моё личное мнение).

Собственно, вопрос в том, насколько перспективен Ruby и есть ли у кого-то обоснованные возражения против того, что «Ruby без рельс бесполезен».

 , ,

DRVTiny
()

Переключить файл для appender'а Log4perl?

Хотелось бы иметь возможность переключать файл, в который пишет Appender, но так, чтобы можно было писать в файл с произвольным именем, а не просто переоткрывать файловый дексриптор на то же имя.

Честно, лень сильно ковырять на эту тему исходники Log4perl. Может, делал уже кто такую фишку?

Понятно, что можно поменять настройки Log4perl и сделать весь init заново, но... вероятно, должен быть более простой способ?

 log4perl,

DRVTiny
()

(Есть ли) система мониторинга, обсчитывающая граф объектов мониторинга?

Знаю, что есть такое в Spectrum и там это довольно удобно реализовано, но в открытых/бесплатных системах мониторинга не встречал.

В самом общем виде нужно следующее:

1) Инструменты, позволяющие тем или иным способом выстраивать объекты мониторинга в связные графы, показывая таким образом зависимости между объектами в различных разрезах ресурсно-сервисной модели

2) Движок системы мониторинга должен быть привязан к графам рессурсно-сервисной модели и способен делать «свёртки» триггеров на основании РСМ. Классический пример: если «упал» маршрутизатор, недоступность сетевого железа за ним не должна порождать миллиард триггеров и лавину всевозможного флуда

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

В очень условно opensource'ном Zabbix'е, например, ресурсно-сервисная модель живёт вообще отдельно от так называемых «карт»/maps - при этом РСМ - это абстрактное дерево, где только листья привязаны хоть к чему-то, вся остальная структура висит в полном вакууме.

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

 , ,

DRVTiny
()

Как определить, что код выполняется в секции BEGIN {}?

У меня есть функция, которая считывает конфигурационный файл и на основе переменной PERL_LIBS в нём добавляет в @INC новые пути.

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

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

Не углубляясь в рассуждения о том, как бы нам обустроить bashrc и /etc/profile.d - скажите, а есть ли теоретическая возможность «общего плана» узнать, на данный момент код работает в BEGIN {}, в каком-нибудь END {} или вообще в основной секции кода?

Спасибо!

 

DRVTiny
()

А чем плох синтаксис современного BASIC?

Прежде всего речь о FreeBASIC.

На мой скромный взгляд, синтаксис весьма хорош и только местами излишне многословен.

Пример неудачного синтакиса (но ИМХО далеко не худшего) :

' Предварительное объявление функции 
' Перегружен по количеству символов
declare function getSomething () as integer
' Но зато можно отличить функцию от процедуры, и это хорошо:
declare sub doSomething ()
' А ещё аргументы читаются по-человечески:
declare function getSomebody (ByVal id as long, ByRef person as PersonalCard) as string

Примеры удачного синтаксиса:

for i=100 to 0 step -1
 for j=20 to 40 step 5
  ...
 next j
next i 
' can be written as "next"

do until A>B
...
loop

do
...
loop until A>B

do while A>B
...
loop

if A>B then
...
else if C>D
...
end if

For i As Integer = 1 To N
    Select Case i
    Case 1, 3, 5, 7, 9
        dummy += 1
    Case 2, 4, 6, 8, 10
        dummy += 1
    Case 11 To 20
        dummy += 1
    Case 21 To 30
        dummy += 1
    Case 31
        dummy += 1
    Case 32
        dummy += 1
    Case 33
        dummy += 1
    Case Is >= 34
        dummy += 1
    Case Else
        Print "can't happen"
    End Select
Next

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

Так почему же ныне так популярен обфусцированный вырвиглазный синтаксис?

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

 ,

DRVTiny
()

Как потоком сжимать данные, отправлямые в сокет?

Попробовал IO::Compress::Gzip->new($sock) - что-то не работает оно так совсем. Уж и autoflush ставил, и убирал - ничего не помогает :(

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

Искал в гугле IO::Compress::Gzip socket - ничего не нашёл.

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

Ну и в целом - есть ли вообще какая-то общеизвестная методика, как сжимать ответы и отправлять их в сокет? У меня всё отлично работает в ту сторону: исходные данные клиента жмутся, всё ОК. Но вот в обратку/ответами что-то какой-то лютый треш происходит: приходит только небольшая порция неконсистентных данных.

 , ,

DRVTiny
()

Потоки в Julia: зелёные или нормальные?

Собственно, весь вопрос в заголовке: из официальной документации непонятно, являются ли экспериментально реализованные потоки в языке julia настоящими или же это очередная кооперативная фикция, зелёная и в пупырышках. Просто если последнее, то я даже смотреть в сторону этой фигни не стану (в Julia отлично реализовано взаимодействие форкнутых процессов), если же процессы основаны на pthreads или чём-то подобном, то это круто и весьма интересно.

 greenshit, , ,

DRVTiny
()

Гарантированно асинхронная запись в Linux?

Вопрос прост как 3 копейки:

Есть ли в Linux системный вызов «запиши в файловый дескриптор вот эти 4096 байт, но не блокируй меня на всё время записи, а отправь 4096 байт в буфер на стороне ядра и вот тебе коллбек, который нужно будет вызвать у меня, когда реальная запись будет завершена».

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

К чему вопрос? К тому, что легко и просто находится select, позволяющий начать запись только тогда, когда не нужно будет ждать завершения чьей-то предыдущей записи - и это прекрасно. Но хотелось бы и саму запись в асинхронном режиме: я просто отправляю в буферы ядра данные для записи, и после этого мне «хоть трава не расти» - я могу свободно заниматься дальнейшей полезной работой.

Наверняка же есть такое?

 , , ,

DRVTiny
()

Как перетаскивать shard'ы туда, где нет интернетов?

Думаю развернуть в порядке эксперимента небольшой «кристальный» веб-сервер с Kemal'ем на борту.

Но есть с(т)ран(н)ая затыка с этим: эта штука будет реально полезной только в закрытом сегменте сети. Мало того, даже если я её настрою в открытом сегменте, всё равно придётся перетаскивать в закрытый. Закрытый - это без всякого доступа к интернетам, понятное дело.

Если инфраструктуру Perl со всеми его кишками, разбросанными по файловой системе, я уже поднаторел перетаскивать tar-архивами, то вот с Crystal'ом как-то не был доселе знаком, и насколько его инфраструктура может быть portable+internet-free - я не в курсе.

Насколько просто ставить пакеты crystal на одной машине и перетаскивать на другую? И вообще есть ли какая-то идеологическая методологи на эту тему: например, возможно, мне было бы удобнее сваливать все shards на один ftp-сервер и раздавать их локально каким-то образом (хотя с perl'ом никогда так не заморачивался, всегда просто файлики таскал архивами).

P.S. Конечно, было бы здорово, если бы программисты не считали, что SPEC'и - зло и собирали нормальные rpm- или deb- пакеты хотя бы, но да, не в этой жизни. У них там «зелёные треды» же и прочие абстракции в системном вакууме, опускаться до сборки пакетов они точно не станут.

 ,

DRVTiny
()

Возможен ли нормальный синтаксис присваивания значения свойству объекта?

Нужно вот так:

$obj->property=$value;

В действительности же Perl 5 со всеми своими музями и мышами не может предложить ничего лучше:

$obj->property($value);

В простых случаях я благополучно обходил это использованием «sub :lvalue», но проблема в том, что такой подход не работает, если нужно проконтролировать, что присваивается свойству объекта или, тем паче, если нужно как-то отреагировать на изменение свойства (бумага->температура_поверхности_ф=451).

Собственно, я так понимаю, что слабая надежда может быть только на tied variable, возвращаемую методом с типом :lvalue? Т.е. tied variable сама проверит, присваивают ли ей что-то разумное или нет, а если нет - выдаст confess/die.

Пока не пробовал, каюсь, но интересно вообще глобальное мнение на тему того, как обойти ограничения lvalue-sub'ов в perl.

Спасибо!

ОТВЕТ:

#!/usr/bin/perl
package O::O;
use Sentinel;

sub new {
  bless {"p"=>"v"}, shift
}

sub p :lvalue {
  sentinel obj=>shift,
           get=>"get_p",
           set=>"set_p";
}

sub get_p {
  $_[0]->{"p"}
}

sub set_p {
  die 'FYAH!' if $_[1]==5;
  $_[0]->{"p"}=$_[1]
}

package main;

my $O=O::O->new();

$O->p=6;

print $O->p,"\n";

$O->p=5;

 

DRVTiny
()

В каком ЯП есть ассоциативные массивы с «нечёткими ключами»?

Собственно, хотелось бы чего-то вроде:

hash=[
 (regex)'^(any|key|be|no|key)$' => 'value',
 'hello'=>'world',
 (glob)'foo*bar'=>'Dummy staff'
]
console.write(
  hash['any'],
  hash['hello'],
  hash['fooizmus lebart']
)

Я понимаю, что «не нужно», но у меня также есть представление о ненужности тех или иных технологий в программировании.

Меня интересует, видел ли кто-либо что-то подобное в существующих языках или нет?

Спасибо!

p.s. Просьба switch, case и given не предлагать :) Речь не об управляющих конструкциях, что бы они там ни возвращали, а именно об инструменте построения гибких ассоциативных массивов.

 , закапывайте,

DRVTiny
()

Кеш = метка времени + данные: как лучше хранить в Redis?

Задача: есть кешированный результат запроса (тяжёлый результат), есть метка времени его актуальности. Redis работает на одной машине вместе с приложением, соотв. «сетевые задержки» очень условны.

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

Вопрос в том, как хранить метку времени и данные: хешем с полями ts и payload, двумя ключами вида object_id:ts и object_id:payload или вообще - метки времени в одной базе Redis, а кешированные данные в другой.

Мне было бы удобнее хранить как хеш, но поклонники Redis, насколько я знаю, хеши не любят и практически не используют. Поэтому я и думаю: раз не любят - есть за что? Например, не приведёт ли чтение только поля ts из хеша к тому, что в действительности «внутри себя» Redis считает всё значение целиком, потом десериализует из какого-нибудь MessagePack'а, после чего отдаст мне ts, параллельно закачав в ОЗУ ещё и весь payload?

Подход с замусориванием Redis составными ключами мне тоже кажется кривым: понятно, что это как минимум влияет на скорость работы поиска по заданному ключу: даже если там скорость поиска прямо равна O(N), всё равно в 2 раза больше ключей - пусть не в 2 раза, но всё-таки замедлит поиск.

Вопрос в том, есть ли какой-то «закешированный» best practice на этот совершенно типичный, на мой взгляд, случай? Безусловно, я могу полезть прямо в код Redis'а, почитать, как оно там устроено, но во-первых я не силён в сях, а во-вторых - если есть уже некий готовый, обоснованный подход, почему бы его не использовать (форумы для того и нужны, чтобы можно было делиться «пережёванными» результатами получения знаний).

В общем, «как лучше»?

Спасибо!

 

DRVTiny
()

Простейший dummy-эмулятор работы smtp, http, imap, ftp, pop3

Здравствуйте!

Есть Zabbix, который умеет примитивно тестировать доступность базовых интернет-сервисов.

Есть машинка во внешней сети, куда надо коннектиться и проверять на ней «как бы сервисы» на доступность.

Для чего это нужно? У нас периодически накрывается инет. Из-за крайне запутанной конфигурации корпоративного фаерволла бывает, что на выход перекрываются какие-то отдельные порты (например, 993=imaps) - и пока какой-нибудь паользователь не возопит - никто и не узнает о том, что накрылся доступ именно по порту (у остальных-то «в браузерах интернеты работают»).

Соотв., мне НЕ нужен мудрёный honey pot и что-то такое антихакерское, мне нужен простейшим образом имитирующий работу кучи сетевых служб демон. Демон будет прикрыт фаерволлом, но даже если бы и не был - если его никто не будет супер-настойчиво DDoS'ить - ничего страшного не произойдёт, по этому поводу беспокойства нет.

Есть ли что-то подобное готовое или лучше самому написать? Вариант «самому» не нравится тем, что если хакеры будет подделывать IP источника и всё-таки DoS'ить, то мой код может быть слишком тормозным, и это приведёт к афекту на реальное приложение, работающее на виртуалке (zabbix proxy).

Загодя весьма признателен! :)

 , ,

DRVTiny
()

Мониторинг очередей Mikrotik

Здравствуйте, коллеги!

Поступила мне задача мониторить Mikrotik, который используется исключительно для отправки внутрикорпоративных SMS-ок.

Что-то стал я погружаться в тему - и обнаружил, что есть масса информации по темам, касающимся мониторинга Mikrotik'а как роутера или изменению каких-то параметров через API... А мне вот надо просто количество SMS-ок, застрявших в очереди, посмотреть.

Покопался в WebFig'е, в каких-то статьях по API - даже намёка на что-то подобное нет.

«И тут я подумал» - вот наверняка же хотя бы уровень GSM-сигнала на антенне можно узнать как-то просто. Но правильным ответом было: «нет, это Mikrotik, и здесь всё, что не компьютерная сеть - просто быть не может».

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

Заранее Гигантское Спасибо!

 , ,

DRVTiny
()

Высвобождение памяти (free) - когда НЕ происходит?

Читал я как-то на заборе, что perl якобы единожды выделенную ему память обратно системе старается не возвращать, а прямо-таки держит до последнего.

Ну написал простенький тест:

#!/usr/bin/perl
use MIME::Base64 qw(encode_base64);
use Time::HiRes qw(sleep);
open my $fh, '<', '/dev/urandom';
my $N=shift or die 'FYAH';
sub fillHash {
  my ($N,$hsh,$fh)=@_;
  my $randBase=$N*10;
  for (1..$N) { 
    read $fh, $s, 1024; 
    $hsh->{int(rand $randBase)}=encode_base64($s);
  }
}

my %H;
while (1) {
  fillHash($N,\%H,$fh);
  sleep 0.2;
  %H=();
}

В итоге, что и логично было бы предположить, потребление памяти не меняется со временем.

Но всё же... в каких ситуациях Perl и в самом деле может не вполне очевидным образом забрать память и не отдать её системе? Скажем так, насколько лениво Perl делает free на структурах данных в примерах, аналогичных моему тесту?

Спасибо!

 

DRVTiny
()

Простенькие и удобные функции логирования

Задумался я как-то невзначай над тем, почему строки для trace и debug формировать труднее всего, но при этом они же чаще всего вообще не выводятся никуда. Ведь несправедливо же: интерпретатор старается, формирует какие-то дампы, куски json'ов вставляет - а мой любимый фремйворк для логирования, Log::Log4perl, всё это радостно сливает в /dev/null.

Также очень не хватало возможности выводить лог-сообщения в нормальном sprintf-стиле: я думаю, многих достала необходимость конкатенации строк для вставки переменных или использования для компиляции строки самой sprintf. Ну неудобно это! Мне куда легче не использовать %s и прочие немногочисленные валидные форматеры printf в тексте лог-сообщений, нежели каждый раз задумываться над тем, как собрать строку лога из разрозненных кусков.

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

Но как-то решил я невзначай порыть исходники этого модуля - и узрел, что там гигантский пласт кода, который делает что-то совершенно хакерски-химерическое (код самого Log::Log4perl проще и понятнее в $N раз), позволяет подключать все подряд фреймворки... Это всё было очень круто конечно, но мне с одной стороны не нужны были другие фреймворки, а с другой - не хотелось бы, чтобы поверх и без того относительно тяжёлого Log::Log4perl ещё гора кода наросла. Ну и встроенная sprintf-функциональность из-за тотальной универсальности логеров ни в одном из них не была реализована, в том числе и в Contextual.

В итоге я сломался и сделал свой велосипед: https://github.com/DRVTiny/Log4perl--KISS

Он позволяет делать как

debug {'String'}
, так и
debug_ 'String'
, что, собственно, мне и было в конечном итоге нужно.

Подробнее - см в SYNOPSIS прилагающегося README.

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

 ,

DRVTiny
()

RSS подписка на новые темы