Page 1 of 2

Using esp_log_set_vprintf() function

Posted: Sat Dec 16, 2017 8:09 am
by kartikkman
Hi I am trying to do Remote Logging for the esp32 .
I have implemented a function to convert the LOG data to the string which I will be sending over the Network .

The problem I am stuck here is to use the esp_log_set_vprintf() ??
DO you have any example or what for the above ??

Code: Select all

void LOG_TO_STRING(const char *format,...)
{
    ESP_LOGI("NO TAG","Call Accepted ");

        char *string;//printf result will be sotred in this     
        va_list arguments_list;
        va_start(arguments_list,format);//Initialiasing the List 
        
                    //Calculating & Allocating Size 
        
                    size_t size_string=snprintf(NULL,0,format,arguments_list);//Calculating the size of the formed string 
                    string=(char *)malloc(size_string+4);//Initialising the string 
                   

                    vsnprintf(string,size_string,format,arguments_list);//Storing the outptut into the string 
                     va_end(arguments_list);//Deinitializing the List 

                     ESP_LOGI("NO TAG","Converted String is :  %s",string);

    free(string);
}

Re: Using esp_log_set_vprintf() function

Posted: Tue Jun 12, 2018 6:31 pm
by kolban
I think to register your function as the logger you would then call:

Code: Select all

esp_log_set_vprintf(LOG_TO_STRING);
in your app code.

Re: Using esp_log_set_vprintf() function

Posted: Tue Jun 12, 2018 6:39 pm
by fly135
Won't this cause a recursive loop?

Code: Select all

void LOG_TO_STRING(const char *format,...)
{
    ESP_LOGI("NO TAG","Call Accepted ");

Re: Using esp_log_set_vprintf() function

Posted: Wed Jun 13, 2018 8:33 am
by papaluna
kartikkmann,

Maybe this example helps, this one writes to SPIFFS.

Code: Select all

    ESP_LOGI(TAG, "  ***Redirecting log output BACK to only UART0 (not to the SPIFFS log file anymore)");
    esp_log_set_vprintf(&vprintf);

Code: Select all

    ESP_LOGI(TAG, "***Redirecting log output to SPIFFS log file (also keep sending logs to UART0)");
    esp_log_set_vprintf(&_log_vprintf);

Code: Select all

// This function will be called by the ESP log library every time ESP_LOG needs to be performed.
//      @important Do NOT use the ESP_LOG* macro's in this function ELSE recursive loop and stack overflow! So use printf() instead for debug messages.
int _log_vprintf(const char *fmt, va_list args) {
    static bool static_fatal_error = false;
    static const uint32_t WRITE_CACHE_CYCLE = 5;
    static uint32_t counter_write = 0;
    int iresult;

    // #1 Write to SPIFFS
    if (_log_remote_fp == NULL) {
        printf("%s() ABORT. file handle _log_remote_fp is NULL\n", __FUNCTION__);
        return -1;
    }
    if (static_fatal_error == false) {
        iresult = vfprintf(_log_remote_fp, fmt, args);
        if (iresult < 0) {
            printf("%s() ABORT. failed vfprintf() -> disable future vfprintf(_log_remote_fp) \n", __FUNCTION__);
            // MARK FATAL
            static_fatal_error = true;
            return iresult;
        }

        // #2 Smart commit after x writes
        counter_write++;
        if (counter_write % WRITE_CACHE_CYCLE == 0) {
            /////printf("%s() fsync'ing log file on SPIFFS (WRITE_CACHE_CYCLE=%u)\n", WRITE_CACHE_CYCLE);
            fsync(fileno(_log_remote_fp));
        }
    }

    // #3 ALWAYS Write to stdout!
    return vprintf(fmt, args);
}

Re: Using esp_log_set_vprintf() function

Posted: Thu Jun 14, 2018 6:52 am
by Vader_Mester
kolban wrote:I think to register your function as the logger you would then call:

Code: Select all

esp_log_set_vprintf(LOG_TO_STRING);
in your app code.
I found this interesting. I'm not 100% sure I get how it works.
It basically sets my own function as the LOG output, so whenever I call any ESP_LOG function it will output using the function I set here?

Correct me if I wrong.
If this is the case, then I found what I was looking for :)

Re: Using esp_log_set_vprintf() function

Posted: Thu Jun 14, 2018 2:13 pm
by kolban
If we think that in C, a function is compiled piece of code that has an entry address ... then we can loosely say that a function is identified by the address in memory where it starts.

When we define a function ... for example:

Code: Select all

void x() {
   printf("Hello World");
}
Not only does this generate code, it "loosely" generates a variable called "x". The value of that variable is the address of the entry point to the function x().

We can declare a variable that can be explicitly a pointer to a function ... for example:

Code: Select all

void (*y)();
and then we can code:

Code: Select all

y = x;
y();
which says that "y" is a variable which holds a pointer to a function. We then assign y the value of x and then "call" the function that is pointed to by "y".


See also:

https://www.geeksforgeeks.org/function-pointer-in-c/

Re: Using esp_log_set_vprintf() function

Posted: Tue Mar 12, 2019 3:06 pm
by GeorgeFlorian1
papaluna wrote:
Wed Jun 13, 2018 8:33 am
kartikkmann,

Maybe this example helps, this one writes to SPIFFS.

Code: Select all

    ESP_LOGI(TAG, "  ***Redirecting log output BACK to only UART0 (not to the SPIFFS log file anymore)");
    esp_log_set_vprintf(&vprintf);

Code: Select all

    ESP_LOGI(TAG, "***Redirecting log output to SPIFFS log file (also keep sending logs to UART0)");
    esp_log_set_vprintf(&_log_vprintf);

Code: Select all

// This function will be called by the ESP log library every time ESP_LOG needs to be performed.
//      @important Do NOT use the ESP_LOG* macro's in this function ELSE recursive loop and stack overflow! So use printf() instead for debug messages.
int _log_vprintf(const char *fmt, va_list args) {
    static bool static_fatal_error = false;
    static const uint32_t WRITE_CACHE_CYCLE = 5;
    static uint32_t counter_write = 0;
    int iresult;

    // #1 Write to SPIFFS
    if (_log_remote_fp == NULL) {
        printf("%s() ABORT. file handle _log_remote_fp is NULL\n", __FUNCTION__);
        return -1;
    }
    if (static_fatal_error == false) {
        iresult = vfprintf(_log_remote_fp, fmt, args);
        if (iresult < 0) {
            printf("%s() ABORT. failed vfprintf() -> disable future vfprintf(_log_remote_fp) \n", __FUNCTION__);
            // MARK FATAL
            static_fatal_error = true;
            return iresult;
        }

        // #2 Smart commit after x writes
        counter_write++;
        if (counter_write % WRITE_CACHE_CYCLE == 0) {
            /////printf("%s() fsync'ing log file on SPIFFS (WRITE_CACHE_CYCLE=%u)\n", WRITE_CACHE_CYCLE);
            fsync(fileno(_log_remote_fp));
        }
    }

    // #3 ALWAYS Write to stdout!
    return vprintf(fmt, args);
}
How does this work ?

I've tried using it inside my code but _log_remote_fp and fileno are undefined.

Also, how many logs can the file hold up ? When does it start deleting old logs ?

Re: Using esp_log_set_vprintf() function

Posted: Tue Mar 12, 2019 3:15 pm
by Deouss
Look at my example - I used esp_log_set_vprintf() function to block incoming logs to com port on PC.

viewtopic.php?f=17&p=39926#p39926

I found out that replacing all log func with my own still allows to use printf() except if you don't save the log messages I guess they are lost.

Re: Using esp_log_set_vprintf() function

Posted: Wed Mar 13, 2019 9:23 am
by GeorgeFlorian1
Deouss wrote:
Tue Mar 12, 2019 3:15 pm
Look at my example - I used esp_log_set_vprintf() function to block incoming logs to com port on PC.

viewtopic.php?f=17&p=39926#p39926

I found out that replacing all log func with my own still allows to use printf() except if you don't save the log messages I guess they are lost.
Hello ! Thank you for your reply !

Your code is still too complex for me. I don't quite understand it yet. I would love a breakdown of how you've replaced the log functions and with what you've replaced them.

I've yet to read about _log_vprintf.

This is my post: viewtopic.php?f=19&t=9666
It would be great to have you take a look at it.
Thank you !

Re: Using esp_log_set_vprintf() function

Posted: Wed Mar 13, 2019 11:58 am
by Deouss
What I've done is quite simple. I substituted printf() function for any logging using esp_log_set_vprintf()
My procedute simply returns 0

Code: Select all

int printf_func(const char* str, va_list vl)
{
    return 0;
}
It should return something like printf(str,vl) I assume
But any printf directs data to uart0 which may break the transmission for other expected data.
I don't think you should call vprintf - only printf - I just assume but never tried it.
I'd say vprintf acts as logging procedure that discards buffers and log queues after some time.
You must save or hold messages by your own procedures