How do I log more than a single string with log4cpp?
E.g. if I want to log all argv's to main:
#include <iostream>
#include <log4cpp/Category.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/PatternLayout.hh>
using namespace std;
int main(int argc, char* argv[]) {
log4cpp::Appender *appender = new log4cpp::FileAppender("FileAppender","mylog");
log4cpp::PatternLayout *layout = new log4cpp::PatternLayout();
layout->setConversionPattern("%d: %p - %m %n");
log4cpp::Category& category = log4cpp::Category::getInstance("Category");
appender->setLayout(layout);
category.setAppender(appender);
category.setPriority(log4cpp::Priority::INFO);
category.info("program started"); // this works fine, I see it in the logfile
for(int i=0; i<argc; ++i) {
// next line does not compile:
category.info("argv["<<i<<"] = '"<<argv[i]<<"'");
}
return 0;
}
the line
category.info("argv["<<i<<"] = '"<<argv[i]<<"'");
does not compile. Obviously the logger does not work as a ostream. What is the log4cpp way to log something like this, preferable at once?
You have two options:
Use printf-style formatting:
for (int i = 0; i < argc; ++i)
{
category.info("argv[%d] = '%s'", i, argv[i]);
}
Use infoStream():
for (int i = 0; i < argc; ++i)
{
category.infoStream() << "argv[" << i << "] = '" << argv[i] << "'";
}
I'd go with the latter.
Related
I try to create 2 matrices: 1 of char* and 1 of THAR*. But for TCHAR* matrix instead of strings I get addresses of some kind. What's wrong?
Code:
#include <tchar.h>
#include <iostream>
using namespace std;
int main(int argc, _TCHAR* argv[])
{
//char
const char* items1[2][2] = {
{"one", "two"},
{"three", "four"},
};
for (size_t i = 0; i < 2; ++i)
{
cout << items1[i][0] << "," << items1[i][1] <<endl;
}
/*
Correct output:
one,two
three,four
*/
//TCHAR attempt
const TCHAR* items2[2][2] = {
{_T("one"), _T("two")},
{_T("three"), _T("four")},
};
for (size_t i = 0; i < 2; ++i)
{
cout << items2[i][0] << "," << items2[i][1] <<endl;
}
/*
Incorrect output:
0046AB14,0046AB1C
0046AB50,0046D8B0
*/
return 0;
}
To fix the issue we need to use wcout for Unicode strings. Using How to cout the std::basic_string<TCHAR> we can create flexible tcout:
#include <tchar.h>
#include <iostream>
using namespace std;
#ifdef UNICODE
wostream& tcout = wcout;
#else
ostream& tcout = cout;
#endif // UNICODE
int main(int argc, _TCHAR* argv[])
{
//char
const char* items1[2][2] = {
{"one", "two"},
{"three", "four"},
};
for (size_t i = 0; i < 2; ++i)
{
tcout << items1[i][0] << "," << items1[i][1] <<endl;
}
/*
Correct output:
one,two
three,four
*/
//TCHAR attempt
const TCHAR* items2[2][2] = {
{_T("one"), _T("two")},
{_T("three"), _T("four")},
};
for (size_t i = 0; i < 2; ++i)
{
tcout << items2[i][0] << "," << items2[i][1] <<endl;
}
/*
Correct output:
one,two
three,four
*/
return 0;
}
I am having a problem in trying to serialize an array of unsigned char into file with GZIP compression using protobuf while playing with the library.
I think the problem might have to do with some of my syntax or misuse of API.
I have also tried std::fstream.
FYI, Windows 8.1 & VS2013 is the building environment.
scene.proto
syntax = "proto3";
package Recipe;
message Scene
{
repeated int32 imageData = 1 [packed=true];
}
source.cpp
#include <iostream>
#include <fstream>
#include <ostream>
#include <istream>
#include <string>
#include <cstdint>
#include "Scene.pb.h"
#include <google\protobuf\io\zero_copy_stream_impl.h>
#include <google\protobuf\io\gzip_stream.h>
int const _MIN = 0;
int const _MAX = 255;
unsigned int const _SIZE = 65200000;
unsigned int const _COMPRESSION_LEVEL = 10;
void randWithinUnsignedCharSize(uint8_t * buffer, unsigned int size)
{
for (size_t i = 0; i < size; ++i)
{
buffer[i] = _MIN + (rand() % static_cast<int>(_MAX - _MIN + 1));
}
}
using namespace google::protobuf::io;
int main()
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
Recipe::Scene * scene = new Recipe::Scene();
uint8_t * imageData = new uint8_t[_SIZE];
randWithinUnsignedCharSize(imageData, _SIZE);
for (size_t i = 0; i < _SIZE; i++)
{
scene->add_imagedata(imageData[i]);
}
std::cout << "scene->imagedata_size() " << scene->imagedata_size() << std::endl;
{
std::ofstream output("scene.art", std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
OstreamOutputStream outputFileStream(&output);
GzipOutputStream::Options options;
options.format = GzipOutputStream::GZIP;
options.compression_level = _COMPRESSION_LEVEL;
GzipOutputStream gzipOutputStream(&outputFileStream, options);
if (!scene->SerializeToZeroCopyStream(&gzipOutputStream)) {
std::cerr << "Failed to write scene." << std::endl;
return -1;
}
}
Recipe::Scene * scene1 = new Recipe::Scene();
{
std::ifstream input("scene.art", std::ifstream::in | std::ifstream::binary);
IstreamInputStream inputFileStream(&input);
GzipInputStream gzipInputStream(&inputFileStream);
if (!scene1->ParseFromZeroCopyStream(&gzipInputStream)) {
std::cerr << "Failed to parse scene." << std::endl;
return -1;
}
}
std::cout << "scene1->imagedata_size() " << scene1->imagedata_size() <<std::endl;
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
You seem to have a typo in your code. Compression level is according to documentation in range 0-9. You set incorrectly compression level to 10.
Your example is working for me when corrected to:
unsigned int const _COMPRESSION_LEVEL = 9;
I have written some codes to load 1025 images with OpenCV to process them;these codes are in two versions :
single thread and multi threads; problem is that the results of codes have confused me; because single thread version is faster than multi threads.
What do you think about it?? what's wrong ?
my codes are below.
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <iostream>
#include "ctpl.h"
using namespace std;
using namespace cv;
#define threaded
void loadImage(int id, int param0) {
stringstream stream;
stream << "/home/me/Desktop/Pics/pic (" << param0 << ").jpg";
Mat x = imread(stream.str(), IMREAD_REDUCED_COLOR_8);
}
int main() {
#ifdef threaded
ctpl::thread_pool p(8);
for (int i = 1; i <= 1025; i++) {
p.push(loadImage,i);
}
// for (int i = 0; i < 1025; ++i) {
// pthread_join(threads[i], NULL);
// }
#else
for (int i = 1; i <= 1025; i++) {
stringstream stream;
stream << "/home/me/Desktop/Pics/pic (" << i << ").jpg";
Mat x = imread(stream.str(), IMREAD_REDUCED_COLOR_8);
}
#endif
return 0;
}
Loop isn't making 10 copies and i have no idea how to change file names
#include "iostream"
#include "fstream"
#include "windows.h"
using namespace std;
void main()
{
char str[200];
ifstream myfile("as-1.txt");
if (!myfile)
{
cerr << "file not opening";
exit(1);
}
for (int i = 0; i < 10; i++)
{
ofstream myfile2("as-2.txt");
while (!myfile.eof())
{
myfile.getline(str, 200);
myfile2 << str << endl;
}
}
system("pause");
}
Solution using plain C API from <cstdio>. Easily customizable.
const char* file_name_format = "as-%d.txt"; //Change that if you need different name pattern
const char* original_file_name = "as-1.txt"; //Original file
const size_t max_file_name = 255;
FILE* original_file = fopen(original_file_name, "r+");
if(!original_file)
//file not found, handle error
fseek(original_file, 0, SEEK_END); //(*)
long file_size = ftell(original_file);
fseek(original_file, 0, SEEK_SET);
char* original_content = (char*)malloc(file_size);
fread(original_content, file_size, 1, original_file);
fclose(original_file);
size_t copies_num = 10;
size_t first_copy_number = 2;
char file_name[max_file_name];
for(size_t n = first_copy_number; n < first_copy_number + copies_num; ++n)
{
snprintf(file_name, max_file_name, file_name_format, n);
FILE* file = fopen(file_name, "w");
fwrite(original_content, file_size, 1, file);
fclose(file);
}
free(original_content);
(*) As noted on this page, SEEK_END may not necessarily be supported (i.e. it is not a portable solution). However most POSIX-compliant systems (including the most popular Linux distros), Windows family and OSX support this without any problems.
Oh, and one more thing. This line
while (!myfile.eof())
is not quite correct. Read this question - it explains why you shouldn't write such code.
int main()
{
const int copies_of_file = 10;
for (int i = 1; i <= copies_of_file; ++i)
{
std::ostringstream name;
name << "filename as-" << i << ".txt";
std::ofstream ofile(name.str().c_str());
ofile.close();
}
return 0;
}
That will make 10 copies of a blank .txt file named "filename as-1.txt" "filename as-2.txt" etc.
Note also the use of int main: main always has a return of int, never void
What's the correct way to add a character array to a constant character array in C++?
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
int pathSize = 0;
char* pathEnd = &argv[0][0];
while(argv[0][pathSize] != '\0') {
if(argv[0][pathSize++] == '/')
pathEnd = &argv[0][0] + pathSize;
}
pathSize = pathEnd - &argv[0][0];
char *path = new char[pathSize];
for(int i = 0; i < pathSize; i++)
path[i] = argv[0][i];
cout << "Documents Path: " << path + "docs/" << endl; // Line Of Interest
delete[] path;
return 0;
}
This code outputs:
Documents Path: �\
Using 'path' instead of '*path' will give me the compile error:
invalid operands of types ‘char*’ and ‘const char [6]’ to binary ‘operator+’
May I suggest using C++ to begin with, and (Boost) Filesystem for maximum benefits:
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;
int main(int argc, const char *argv[])
{
const std::vector<std::string> args { argv, argv+argc };
path program(args.front());
program = canonical(program);
std::cout << (program.parent_path() / "docs").native();
}
This will use the platform's path separator, know how to translate 'funny' paths (e.g. containing ..\..\, or UNC paths).
Something like this should do it (totally untested):
const char* end = strrchr(argv[0], '/');
std::string docpath = end ? std::string(argv[0], end) : std::string(".");
docpath += '/docs/';
Your way:
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
int pathSize = 0;
char* pathEnd = &argv[0][0];
while(argv[0][pathSize] != '\0') {
if(argv[0][pathSize++] == '/')
pathEnd = &argv[0][0] + pathSize;
}
pathSize = pathEnd - &argv[0][0];
char *path = new char[pathSize + 5]; //make room for "docs/"
for(int i = 0; i < pathSize; i++)
path[i] = argv[0][i];
char append[] = "docs/";
for(int i = 0; i < 5; i++)
path[pathSize+i] = append[i];
cout << "Documents Path: " << path << endl;
function_expecting_charptr(path);
delete[] path;
return 0;
}
Sane C way:
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
char* pathEnd = strrchr(argv[0], '/');
if (pathEnd == NULL)
pathEnd = argv[0];
int pathSize = (pathEnd-argv[0]) + 5; //room for "docs/"
char *path = new char[pathSize];
if (pathSize)
strncpy(path, argv[0], pathSize+1);
strcat(path, "docs/");
cout << "Documents Path: " << path << endl;
function_expecting_charptr(path);
delete[] path;
return 0;
}
C++ way:
#include <iostream>
#include <string>
int main(int argc, char** argv) {
std::string path = argv[0];
size_t sep = path.find('/');
if (sep != std::string::npos)
path.erase(sep+1);
else
path.clear();
path += "docs/";
std::cout << "Documents Path: " << path << endl;
function_expecting_charptr(path.c_str());
return 0;
}
Note that argv[0] holds an implementation defined value, and especially in *nix environments isn't guaranteed to hold anything useful. The first parameter passed to the program is found in argv[1].
I combined some of your guys' ideas into this compact code:
#include <iostream>
#include <cstring>
using namespace std;
int main(int argc, char** argv) {
const string path_this = argv[0];
const string path = path_this.substr(0, strrchr(argv[0], '/') - argv[0] +1);
const string path_docs = path + "docs/";
cout << "Documents Path: " << path_docs << endl;
return 0;
}
To get the character array from this I can then run 'path_docs.c_str()'.
Credits: #MooingDuck, #MarkB, Google.