LINUX.ORG.RU

Кастомные потоки

 , , ,


0

1

Читаю про кастомные потоки.

Во первых смущает:

Portability Note: The facilities described in this section are specific to GNU. Other systems or C implementations might or might not provide equivalent functionality.

Во вторых смущает - а правильного ли я хочу?

А хочу я сделать обертку, которая и выведет в stdout/stderr, и запишет в лог, то что ей передали. Вообще даже три типа хочу кастомных - xx_info, xx_err, xx_debug

Насколько это вменяемо? Реализуемо? Если не вменяемо или не реализуемо, то как правильно? А можно на пальцах? Ато я не особо петрю.

Ответ на: комментарий от anonymous

syslog

Там целый комбайн. На мою маленькую программульку это как комара с пушки.

Пойду пока дальше почитаю про кастомные.

deep-purple ★★★★★
() автор топика

немного не в тему, но реализация wrappers в пхп очень даже недурна. Стоит взглянуть для вдохновения.

anonymous
()

Ничего не понял что ты имел в виду, но никто не мешает сделать помимо >info.log и 2>err.log какой-нибудь 3>debug.log. А ещё man tee на всякий случай.

mix_mix ★★★★★
()

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

slovazap ★★★★★
()
Ответ на: комментарий от deep-purple

т.е. libc использовать — комбайн, а ооп врукопашную — ок? ясно.

anonymous
()
Ответ на: комментарий от mix_mix

man tee на всякий случай

Насколько вменяемо на каждый логовысер дергать exec tee и/или ловить-перенаправлять stderr и прочие?

deep-purple ★★★★★
() автор топика

Можно узнать юзкейс? Если типа перед пацанами понтанутся, то конечно, делай. Но, взять тот же башевский TCP socket to file descriptor, то уже в рамках линукса и даже одно и того же дистрибутива разных версий это может быть скомпиленно, а может и не быть.

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

Кароч я навелосипедил. Без всяких потоков. Не чушь?

#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <sys/time.h>
#include <time.h>


#define xx_perror(...) xx_perror_internal((xx_perror_args){__VA_ARGS__});
// log message types (verbose)
#define XX_LOF 0
#define XX_INF 1
#define XX_WRN 2
#define XX_DBG 3
#define XX_ERR 4


typedef struct {
    char *str;
} xx_perror_args;

struct xx_timer_t {
    time_t tt;
    struct tm tm;
    struct timeval tv;
} xx_timer;

FILE *xx_log_fp;
unsigned xx_verbose = 4;


void
xx_timer_touch(void)
{
    gettimeofday(&xx_timer.tv, NULL);
    xx_timer.tt = time(NULL);
    localtime_r(&xx_timer.tt, &xx_timer.tm);
}

void
xx_timer_fprintf(FILE *stream)
{
    xx_timer_touch();
    fprintf(
        stream,
        "%d-%02d-%02d %02d:%02d:%02d.%06d ",
        xx_timer.tm.tm_year + 1900,
        xx_timer.tm.tm_mon  + 1,
        xx_timer.tm.tm_mday,
        xx_timer.tm.tm_hour,
        xx_timer.tm.tm_min,
        xx_timer.tm.tm_sec,
        xx_timer.tv.tv_usec
    );
}

void
xx_log(const unsigned type, const char *fmt, ...)
{
    if (type == XX_ERR || type <= xx_verbose) {

        va_list args;

        if (type > XX_LOF && xx_log_fp) {
            xx_timer_fprintf(xx_log_fp);
            va_start(args, fmt);
            vfprintf(xx_log_fp, fmt, args);
            va_end(args);
        }
        va_start(args, fmt);
        vfprintf(type == XX_ERR ? stderr : stdout, fmt, args);
        va_end(args);

    }
}

void
xx_perror_internal(xx_perror_args args)
{
    if (errno != 0) {
        if (args.str) {
            xx_log(XX_ERR, "ERR: %s(%d), %s\n", args.str, errno, strerror(errno));
        } else {
            xx_log(XX_ERR, "ERR: (%d) %s\n", errno, strerror(errno));
        }
    }
}

int
main (int argc, char **argv)
{
    xx_log_fp = fopen("./xx.log", "a");

    FILE *fp;
    char *fn = "./not-exists.bin";

    xx_log(XX_DBG, "DBG: Try open file: %s\n", fn);
    fp = fopen(fn, "rb");
    if (!fp) {
        xx_perror("fopen");
    }

    return 0;
}

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от anonymous

но велосипед. use syslog, luke

Так и получилось - похоже на сислог.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Для велосипеда неплохо. GNU-измы вроде кастомных потоков в любом случае лучше не использовать и придерживаться С стандарта.

Только оберни все это дело в отдельный модуль и приделай публичный интерфейс вида открыть лог, закрыть лог, записать в лог, установить уровень вербозности. Дефайны XX_ERR, XX_WRN и т.д. лучше енумом сделать. Ну и xx_timer нет смысла делать глобальной переменной.

archie
()
Ответ на: комментарий от archie

xx_timer нет смысла делать глобальной переменной

Как сделать локальной (не, понятно, объявить внутри тела ф-ции)? И, я так понимать, типа «статической», чтоб не переиничивалась, например как-то засунуть в xx_timer_touch(). На пальцах пояснить можешь?

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от archie

Ещё может быть такая тонкость:

Ошибка должна попасть в общий лог, лог дебага и лог ошибок; обычная запись - в общий лог и лог дебага; дебажная запись - только в дебажный лог.

Удобно иметь по функции на логирование каждого типа записи -Log(), LogDebug(), LogError() в которых хардкодится это поведение.

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

LogError(VERB_STD, «Стандартное сообщение об ошибке»);
LogError(VERB_EXT," Его расширенное пояснение");

bogus_result
()
Ответ на: комментарий от deep-purple

Хех. Опять же если ты гоняешь текст, то какой смысл в вымышленном потоке? Весь смысл в том, что ты фигачишь в нужный поток в нужном формате. Без юзкейса это, имхо, бесмысленно. Например, юзкейс: гонять все по UDP.

А так, то чем не угодили пайпы? Неужели сложно сделать так:

./my_prog --log-file=/tmp/prog.log | grep bla-bla-bla
Т.о. пишем в лог + отдаем grep все в неотформатированном виде. Как вычислить используешь ты stdout под пайпом или нет дело плевое — смотришь исходники того же grep.

И вообще, если делать «новый» крутой логгер, то бери аналог тоже log4j. Уж столько аналогов понаписали...

gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 2)
Ответ на: комментарий от gh0stwizard

Нене, это все JFF. Я просто разбираюсь с (гну)сями, учусь. А чтобы изучать, нужна какая-то практика и цель. Вот я и определился - что должно быть в болемене приличной прилаге? Правильно - логи, сигналы, треды/форки, демонизация, общение сокетами/пайпами. Ну вот, попиливаю почуть.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

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

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

то лучше брать готовое

Не понимая как оно вообще работает? Тут лучше навелосипедить что-то небольшое, попутно разобравшись в low-level чем втуплять на кучу чужого не понятного кода.

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Не понимая как оно вообще работает?

Чем меньше знаешь, тем крепче спишь. И голова не болит (с)

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

gh0stwizard ★★★★★
()
Ответ на: комментарий от deep-purple

Кароч я навелосипедил. Без всяких потоков. Не чушь?

Зачем ты пытаешься писать как ублюдок и им подражать?

Это паста убогого и ублюдского стиля - жалкое подражательство, как можно его юзать, когда тебя не заставляют?

Этот убогий с89, который протух столетвобед.

typedef struct {
    char *str;
} xx_perror_args; //зачем?

#define xx_perror(...) xx_perror_internal((xx_perror_args){__VA_ARGS__});//неосиляторство

#define XX_LOF 0//ублюдкие макросы, причем тотально бесполезные.
xx_log()// так вменяемые люди не пишут.

(errno != 0)// убожество.
if (!fp)//даже в 10строчках общей логики нет.
xx_timer.tt = time(NULL);//о да.

Толку от говнища вместо велосипеда?

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

Даже захреначу тебе псевдокод:

typedef enum {err = 0, wrn} type_t;

typedef struct {
  FILE * stream;
  void(*f)(FILE *, char *);
} type_data_t;

typedef struct {
  type_data_t get[2];
} global_tdata_t;

global_tdata_t global_tdata;

void _err(FILE * stream, char * msg) {
  return fprintf(stream, "ERROR: %s\n", msg);
}

void _wrn(FILE * stream, char * msg) {
  return fprintf(stream, "WARNING: %s\n", msg);
}

extern inline __attribute__((__gnu_inline__)) void fproxy(type_t type, char * format, ...) {
  type_data_t t = global_tdata.get[type];
  char buf[100500];
  sprintf(buf, format, __builtin_va_arg_pack());
  return t.f(stderr, buf);
}

int main(void) {
  global_tdata = (global_tdata_t){(type_data_t){stderr, _err}, (type_data_t){stdout, _wrn}};
  
  char * fn = "./not-exists.bin";
  fproxy(wrn, "Try open file %s", fn);
  if(!fopen(fn, "rb"))
    fproxy(err, "%s(%d), %s", fn, errno, strerror(errno));
}

В примитивнум случае как-то так. Особо не проверял.

anonymous
()
Ответ на: комментарий от gh0stwizard

Чем меньше знаешь, тем крепче спишь. И голова не болит (с)

То-то я думаю, почему везде одно кривое, глючащие, тормазное и дырявое говно.

anonymous
()
Ответ на: комментарий от anonymous

Этот убогий с89

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

#define xx_perror(...) xx_perror_internal((xx_perror_args){__VA_ARGS__});//неосиляторство

Ну, вот так закостылил, ибо «убогий с89» не может «fn(...)», а может только «fn(blah required_first_arg, ...)»

xx_perror_args; //зачем?

Для костыля, ибо «убогий с89». Вроде как и стандартный perror сделан так же, насколько я понял глядая в сорцы.

#define XX_LOF 0//ублюдкие макросы

Давно исправлено на enum

(errno != 0)// убожество

В xx_perror я посчитал что нет смысла срать в stderr и лог если ошибки и не было. Ну да, можно убрать совсем, а тот кто дёрнет просто так - ССЗБ.

if (!fp) ---> if (!fopen(fn, «rb»))

Эй, а кто будет дескриптор сохранять для дальнейших действий?

xx_timer.tt = time(NULL);//о да

А как правильно?

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

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

Вы издеваетесь надо мною? Чего последовательным? Это не изучение - это говно. Это не последовательное изучение - это изучение того, что является а) неактуальным, б) вредным и дырявым говном, в) зиждится на подходах, которые так же неактуальны и вредны.

Это протухшее и не нужное говно, а читать и понимать его ты итак научишься, ибо на это говне написано 99% кода.

Ну, вот так закостылил, ибо «убогий с89» не может «fn(...)», а может только «fn(blah required_first_arg, ...)»

Только вот у тебя тут нет ни первого ни второго.

Для костыля, ибо «убогий с89». Вроде как и стандартный perror сделан так же, насколько я понял глядая в сорцы.

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

В xx_perror я посчитал что нет смысла срать в stderr и лог если ошибки и не было. Ну да, можно убрать совсем, а тот кто дёрнет просто так - ССЗБ.

Дело не в этом - я говорю не о логике твоей программы.

Зачем ты пишешь ifУБЛЮДСКИЙ_ПРОБЕЛ(errno != 0), если if(errno) делает тоже самое?

Эй, а кто будет дескриптор сохранять для дальнейших действий?

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

Эй, а дальнейшие действия у меня есть? Когда будут - тогда будет и эй.

Ты написал в одном месте ifУБЛЮДСКИЙ_ПРОБЕЛ(errno != 0), а втором не ifУБЛЮДСКИЙ_ПРОБЕЛ(errno == 0) - т.е. 0последовательности даже в 10строчках.

А как правильно?

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

anonymous
()
Ответ на: комментарий от anonymous

Только вот у тебя тут нет ни первого ни второго

Поясни неучу.

Дело не в этом - я говорю не о логике твоей программы

Тогда и тут я не в курсе, поясни.

Зачем ты пишешь ifУБЛЮДСКИЙ_ПРОБЕЛ(

Какому принятому стандарту это противоречит? Дай ссыль почитать, приму к сведению, исправлюсь.

Когда будут - тогда будет и эй

Ок, значит там снова было про пробел.

дак ты его даже не юзаешь

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

deep-purple ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Поясни неучу.

Что мне тебе пояснить? Это ты мне должен пояснить к чему ты высрал какие-то fn(...), если у тебя fn(xx_perror_args).

Давай ещё раз, просто один аргумент, если ты не понял.

Тогда и тут я не в курсе, поясни.

Чего тебе пояснить? Тебе сказали, что то, что ты высрал к моему замечанию не имеет никакого отношения. Тебе это не ясно?

Суть моего замечания в том, что if(a != 0), а не if(a) пишут только конченные ублюдки.

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

Чего стандарту? О5 эти говносливы. Куда же этот «стандарт» должен быть принят?

Здравый смысл пойдёт за стандарт? Хотя у 99% бабуинов он не принят. Тыж даже не осилишь аргументировать мне за ублюский пробел - ты просто его ставишь, ибо так пишут гнутые ублюдки. Собственно как и переводы строки после типа возврата функции.

Ок, значит там снова было про пробел.

Нет, ты было не про пробел и если тебе это не ясно, то ты выбрал не ту профессию. Нахрен ты мне тут юлишь неся херню?

Юзаю, вглядись, в кансоль не выводит, а в логфайл всовывает дату-время мессаги.

Не юзаешь ты собственно его результат вне апдейта твоей структуры. И да, что же возвращает gettimeofday(), кроме tv_usec? А что принимает локалтайм?

anonymous
()
Ответ на: комментарий от deep-purple

Не кукайрекай о том, в чем нихрена не понимаешь. Повторю тебе уже 3-й раз.

anonymous
()
Ответ на: комментарий от anonymous

к чему ты высрал какие-то fn(...)

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

if(a != 0), а не if(a)

В своем варианте я точно вижу что проверяется signed! инт, а не хрен пойми чего.

Здравый смысл пойдёт за стандарт?

Нет, подойдет аргументация, почему не нужно (нельзя) ставить пробел.

было не про пробел

Так ты не поясняешь. Я только предполагаю. Из того что ты все про пробелы разорался, я так и предположил - опять пробел не нравится.

Не юзаешь вне апдейта твоей структуры

Верно, буду юзать в более чем одном месте, а перед юзом буду дергать в тех местах её апдейт.

что же возвращает gettimeofday(), кроме tv_usec? А что принимает локалтайм?

gettimeofday() return 0 for success, or -1 for failure. В моем случае заполняет структуру timeval. Локалтайм на основе переданной time_t заполняет структуру tm (да, можно забрать и из возврата локалтайма). Есть способ сделать это проще-лучше-короче-правильнее - покажи.

deep-purple ★★★★★
() автор топика
Последнее исправление: deep-purple (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.