46

In Android-ndk, we could use "__android_log_write", "__android_log_print", ... etc to output messages to the "LogCat" window. How about if I use "std::cout" to output some strings ? E.g.

std::cout << "some strings" << std::endl;

Where would the strings be sent.

It seems that Android does not have Console Applications and the above strings may not be sent. Could I redirect the "stdout" to a file so that sending strings to "std::cout" is equivalent to logging messages ?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
user1129812
  • 2,859
  • 8
  • 32
  • 45

5 Answers5

41

You can create a class derived from std::streambuf which uses the Android specific functions to send the produced sequence of characters. I don't know where the default implementation of std::cout sends characters on Android, however. Basically, this would look something like this:

class androidbuf : public std::streambuf {
public:
    enum { bufsize = 128 }; // ... or some other suitable buffer size
    androidbuf() { this->setp(buffer, buffer + bufsize - 1); }

private:
    int overflow(int c)
    {
        if (c == traits_type::eof()) {
            *this->pptr() = traits_type::to_char_type(c);
            this->sbumpc();
        }
        return this->sync()? traits_type::eof(): traits_type::not_eof(c);
    }

    int sync()
    {
        int rc = 0;
        if (this->pbase() != this->pptr()) {
            char writebuf[bufsize+1];
            memcpy(writebuf, this->pbase(), this->pptr() - this->pbase());
            writebuf[this->pptr() - this->pbase()] = '\0';

            rc = __android_log_write(ANDROID_LOG_INFO, "std", writebuf) > 0;
            this->setp(buffer, buffer + bufsize - 1);
        }
        return rc;
    }

    char buffer[bufsize];
};

To actually set up std::cout to write to this stream buffer, you would do something like this in your main() function:

int main() {
    std::cout.rdbuf(new androidbuf);
    ...
}

This create a memory leak for the one androidbuf stream which is, however, somewhat intentional: the stream may be written to after main() is exited and it is flushed when when std::cout gets destroyed. If you don't want this, you could either restore std::cout's original stream buffer or set it to null and delete the return from rdbuf():

   // avoid a one-time resource leak but don't get output afterwards:
   delete std::cout.rdbuf(0);
Zsolt Szatmari
  • 1,219
  • 1
  • 12
  • 29
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Thanks for another solution. But it involves more coding, I'll try it later. – user1129812 Jan 16 '12 at 00:05
  • 3
    Thank you, it's works. But it has several mistakes. Here is fixed version: https://gist.github.com/dzhioev/6127982 – dzhioev Aug 01 '13 at 02:31
  • Thanks! I modified the code to actually work by copy&paste, hope it might help someone. (might be pending peer review) – Zsolt Szatmari Oct 06 '14 at 13:22
  • Wow, you just made my life 100% easier! I wish I could give you more than an upvote – Chris Jan 09 '15 at 06:44
  • For me the code only displays the log when the buffer is full. – pvallet Jul 15 '17 at 10:37
  • 1
    @pvallet: Yes, that is expected unless the stream is explicitly flushed, e.g., using `out << std::flush`. Sending character to external destinations is generally rather expensive and is normally minimized. You *can* disable the buffer in `androidbuf` causing `overflow()` to be called for each character (also introducing some extra overhead) and call `sync()` upon specific characters, e.g., `'\n'`. However, I'd stick with flushing the stream explicitly. – Dietmar Kühl Jul 15 '17 at 12:57
  • 1
    If someone is interested in flushing the buffer after every output, try this: std::cout.setf(std::ios::unitbuf); – Zbyl Jan 28 '18 at 02:24
33

According to the Android documentation, stdout & stderr output to /dev/null. You can use the Android Debug Bridge to achieve what you want.

By default, the Android system sends stdout and stderr (System.out and System.err) output to /dev/null. In processes that run the Dalvik VM, you can have the system write a copy of the output to the log file. In this case, the system writes the messages to the log using the log tags stdout and stderr, both with priority I. To route the output in this way, you stop a running emulator/device instance and then use the shell command setprop to enable the redirection of output. Here's how you do it:

$ adb shell stop
$ adb shell setprop log.redirect-stdio true
$ adb shell start

The system retains this setting until you terminate the emulator/device instance. To use the setting as a default on the emulator/device instance, you can add an entry to /data/local.prop on the device.

parapura rajkumar
  • 24,045
  • 1
  • 55
  • 85
4

Another option:

#include <sstream>

class MyStream
{
private:
   std::stringstream m_ss;
   int m_logLevel;
public:

   MyStream(int Xi_logLevel)
   {
      m_logLevel = Xi_logLevel;
   };
   ~MyStream()
   {
      __android_log_print(m_logLevel,LOG_TAG,"%s", m_ss.str().c_str());
   }

   template<typename T> MyStream& operator<<(T const& Xi_val)
   {
      m_ss << Xi_val;
      return *this;
   }
};

#define MY_LOG(LOG_LEVEL) MyStream(ANDROID_LOG_##LOG_LEVEL) << __FUNCTION__ << ":" << __LINE__ << " : "

PROS:

(1) The messages are printed immediately.

CONS:

(1) You must to change your code (std::cout -> MY_LOG(X)).

(2) Each a single print produces an object and destroys it.

(*** This answer base on this answer)

Community
  • 1
  • 1
y30
  • 722
  • 7
  • 17
2

The answer of Dietmar Kühl is very good, but it do not work with boost.log from Crystax NDK. I found another idea and have corrected it a little. Here is the code:

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <android/log.h>

static int pfd[2];
static pthread_t thr;
static const char *tag = "myapp";

static void *thread_func(void*)
{
    ssize_t rdsz;
    char buf[128];
    while((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) {
        if(buf[rdsz - 1] == '\n') --rdsz;
        buf[rdsz] = 0;  /* add null-terminator */
        __android_log_write(ANDROID_LOG_DEBUG, tag, buf);
    }
    return 0;
}

int start_logger(const char *app_name)
{
    tag = app_name;

    /* make stdout line-buffered and stderr unbuffered */
    setvbuf(stdout, 0, _IOLBF, 0);
    setvbuf(stderr, 0, _IONBF, 0);

    /* create the pipe and redirect stdout and stderr */
    pipe(pfd);
    dup2(pfd[1], 1);
    dup2(pfd[1], 2);

    /* spawn the logging thread */
    if(pthread_create(&thr, 0, thread_func, 0) == -1)
        return -1;
    pthread_detach(thr);
    return 0;
}

And its use:

...
start_logger("MyApp");
...

Now all output from boost.log to std::cout and std::cerr will be in logcat:

#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/sources/logger.hpp>

...
boost::log::add_console_log(std::cout);
boost::log::add_common_attributes();

boost::log::sources::logger_mt lg;
BOOST_LOG(lg) << "Hello, World!";
...
NikitaFeodonit
  • 165
  • 1
  • 10
0

Simple way to print log in android studio logcat.

Step 1: Add the following lines to your common header file.

#include <android/log.h>
    
#define LOGV(TAG, ...) __android_log_print(ANDROID_LOG_VERBOSE, TAG,__VA_ARGS__)
#define LOGD(TAG, ...) __android_log_print(ANDROID_LOG_DEBUG  , TAG,__VA_ARGS__)
#define LOGI(TAG, ...) __android_log_print(ANDROID_LOG_INFO   , TAG,__VA_ARGS__)
#define LOGW(TAG, ...) __android_log_print(ANDROID_LOG_WARN   , TAG,__VA_ARGS__)
#define LOGE(TAG, ...) __android_log_print(ANDROID_LOG_ERROR  , TAG,__VA_ARGS__)

Step 2: Now just call

LOGV("MYTAGNAME", "Hello!!");
LOGD("MYTAGNAME", "Hello!!");
LOGI("MYTAGNAME", "Hello!!");
LOGW("MYTAGNAME", "Hello!!");
LOGE("MYTAGNAME", "Hello!!");

Step 3: you can see logs in logcat as below.

enter image description here

Pratik Tank
  • 2,213
  • 1
  • 17
  • 29