I'm trying to use log4cxx to log my application using RollingFileAppender on a Windows C++ console application. I would like to create a new log file every time the size reaches 1MB. Furthermore, when the desired size is reached, the file should be zipped automatically. The maximum number of files created must be 10; after which older files should be overwritten.
I'm using:
apache-log4cxx-0.10.0
apr-util-1.6.1
apr-1.7.0
This is my code:
log4cxx::rolling::RollingFileAppender* fileAppender1 = new log4cxx::rolling::RollingFileAppender();
fileAppender1->setLayout(log4cxx::LayoutPtr(new log4cxx::PatternLayout(L"[%d{ISO8601}{GMT}] %-4r [%t] %c | %-5p | %m%n")));
fileAppender1->setAppend(true);
log4cxx::helpers::Pool p;
fileAppender1->activateOptions(p);
log4cxx::rolling::FixedWindowRollingPolicy* rollingPolicy = new log4cxx::rolling::FixedWindowRollingPolicy();
rollingPolicy->setMinIndex(1);
rollingPolicy->setMaxIndex(10);
rollingPolicy->setFileNamePattern(L"j_log_%i.log");
log4cxx::rolling::SizeBasedTriggeringPolicy* triggerPolicy = new log4cxx::rolling::SizeBasedTriggeringPolicy();
triggerPolicy->setMaxFileSize(1024*1024);
fileAppender1->setRollingPolicy(rollingPolicy);
fileAppender1->setTriggeringPolicy(triggerPolicy);
LoggerPtr logger(Logger::getLogger("LogConsole1"));
logger->addAppender(fileAppender1);
logger->setLevel(log4cxx::Level::getTrace());
for (int i = 0; i < 10000; i++)
{
LOG4CXX_INFO(logger, "Created FileAppender appender");
LOG4CXX_INFO(logger, "LOGGER1");
}
The result obtained is a file named ".1" (without any extension) with such content (it seems ok):
[2019-09-13 07:44:58,619] 21063 [0x00003e14] LogConsole1 | INFO | Created FileAppender appender
[2019-09-13 07:44:58,622] 21066 [0x00003e14] LogConsole1 | INFO | LOGGER1
The problems are:
The file does not have the proper name
The file does not roll over (only one file is created also if its size exceeds 1MB)
On the application console I see many exceptions like: "log4cxx: Exception during rollover"
What am I doing wrong?
I do not completely understand your file pattern but the docs do not use the "L" char in their Pattern.
In my projects is use
rollingPolicy->setFileNamePattern("file.%i.log");
sometimes with a string variable which works good.
I can not find the configuration in your code snipped.
As far as i know, you have to setup the appender by using the BasicConfiguration object.
log4cxx::BasicConfigurator::configure(log4cxx::AppenderPtr(yourAppenderPointer));
this will append your appender to the root logger and works for my case.
Here is my full code snippet of my initialize.
void someclass::initLogger(std::string fileName) {
std::string::size_type found = fileName.find(".log");
std::string strippedFileName;
if (found != std::string::npos)
{
strippedFileName = fileName.substr(0, found);
}
else
{
strippedFileName = fileName;
fileName = fileName + ".log";
}
//initializes for rolling file appenders
rollingFileAppender = new log4cxx::rolling::RollingFileAppender();
rollingPolicy = new log4cxx::rolling::FixedWindowRollingPolicy();
rollingPolicy->setMinIndex(1);
rollingPolicy->setMaxIndex(3);
log4cxx::LogString fileNamePattern = strippedFileName + ".%i.log";
rollingPolicy->setFileNamePattern(fileNamePattern);
trigger = new log4cxx::rolling::SizeBasedTriggeringPolicy();
trigger->setMaxFileSize(1024);
rollingFileAppender->setRollingPolicy(rollingPolicy);
rollingFileAppender->setTriggeringPolicy(trigger);
rollingFileAppender->setLayout(log4cxx::LayoutPtr(new log4cxx::PatternLayout(LOGFILE_LAYOUT_PATTERN)));
rollingFileAppender->setFile(fileName);
rollingFileAppender->setAppend(true);
//initializes for a console appender
consoleAppender = new log4cxx::ConsoleAppender(log4cxx::LayoutPtr(new log4cxx::PatternLayout(LOGFILE_LAYOUT_PATTERN)));
log4cxx::helpers::Pool p;
rollingFileAppender->activateOptions(p);
log4cxx::BasicConfigurator::configure(log4cxx::AppenderPtr(consoleAppender));
log4cxx::BasicConfigurator::configure(log4cxx::AppenderPtr(rollingFileAppender));
}
This code prints to a specified file via a rolling file appender and also prints to the terminal using the consoleAppender
This prints file one file with fileName.log and up to three more with fileName.i.log
Related
I'm trying to display the length of audio files in a Playlist component for an application.
I've not used Juce or C++ before, and I can't understand how to do that from Juce documentation.
I want to make a function that takes an audio file's URL and returns the length in seconds of that audio without playing that file or doing anything else with that file.
I've tried a lot of things, and all of them didn't work, and this is the last thing I've tried:
void PlaylistComponent::trackStats(URL audioURL)
{
AudioFormatManager formatManager;
std::unique_ptr<AudioFormatReaderSource> readerSource;
AudioTransportSource transportSource;
auto* reader = formatManager.createReaderFor(audioURL.createInputStream(false));
if (reader != nullptr)
{
std::unique_ptr<AudioFormatReaderSource> newSource(new AudioFormatReaderSource(reader, true));
transportSource.setSource(newSource.get(), 0, nullptr, reader->sampleRate);
readerSource.reset(newSource.release());
DBG("PlaylistComponent::trackStats(URL audioURL): " << transportSource.getLengthInSeconds());
}
else
{
DBG("Something went wrong loading the file");
}
}
And this is the PlaylistComponent header file:
class PlaylistComponent : public juce::Component,
public juce::TableListBoxModel,
public Button::Listener,
public FileDragAndDropTarget
{
...
}
juce::AudioFormatReaderSource has a method called getTotalLength() which returns the total amount of samples.
Divide that by the sample rate of the file and you have the total length in seconds. Something like this:
if (auto* reader = audioFormatReaderSource->getAudioFormatReader())
double lengthInSeconds = static_cast<double> (audioFormatReaderSource->getTotalLength()) / reader->sampleRate;
You can do this very early on in the audio file opening procedure. You only need an AudioFormatReader instance (no need to create an AudioFormatReaderSource):
// create juce::File from a path juce::String (from a drag & drop event etc).
File file{filePath};
// make sure it is a file and not a directory, etc.
if (!file.existsAsFile()) return;
// create the AudioFormatReader that contains the data
AudioFormatReader *reader = formatManagerInstance.createReaderFor(file);
// make sure a valid reader can be created (not an unsupported file)
if (reader == nullptr) return;
// log the length in seconds
std::cout << reader->lengthInSamples / reader->sampleRate << "\n";
Note: for this to work you will need to
have access to your AudioFormatManager instance and
have already registered the format(s) of the file type (usually through a .registerBasicFormats() call on your AudioFormatManager instance.
IMPORTANT: if successful the createReaderFor() method uses new to create a new AudioFormatReaderInstance, so make sure to use delete on it when you are finished using it to avoid memory leaks
I searched everywhere but I can't find sample on how to actually save a file to the system. Threads about opening a Save File dialog box can be read in numerous sites but the successful saving of the user created file to a user selected path is always cut (//add your code here). Please bear with me as I am new in C++ (MFC).
I know I need to actually code the saving of the data to the file path but I just don't know how.
Code snippet (via CFileDialog):
void CTryDlg::OnBnClickedSaveAs()
{
CFileDialog dlg(FALSE);
dlg.m_ofn.nMaxFile = MAX_PATH;
dlg.m_ofn.lpstrFilter = _T("Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0\0");
dlg.m_ofn.lpstrTitle = _T("Save File As");
CString filename;
if (dlg.DoModal() == IDOK)
{
filename = dlg.GetPathName(); // return full path and filename
//write your sample code here to save the file to the user selected path
}
}
Code snippet via GetSaveFileName():
OPENFILENAME SfnInit()
{
OPENFILENAME t_sfn;
char szFileName[MAX_PATH] = "";
ZeroMemory(&t_sfn, sizeof(t_sfn));
t_sfn.lStructSize = sizeof(t_sfn);
t_sfn.hwndOwner = NULL;
t_sfn.lpstrFilter = _T("Text file\0*.txt\0");
t_sfn.lpstrFile = szFileName;
t_sfn.lpstrTitle = _T("Save As\0");
t_sfn.nMaxFile = MAX_PATH;
t_sfn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
t_sfn.lpstrDefExt = _T("Text file\0*.txt\0");
if (GetSaveFileName(&t_sfn2) != true)
{
AfxMessageBox(_T("Saving file canceled!"));
}
else
{
//write your sample code here to save the file to the user selected path
}
}
Anybody who can provide a very simple sample code that could actually save a user desired file (ex: text file) to the user selected path will be greatly appreciated.
I have also read that the program should run as administrator.
Thank you.
Since you are using MFC, I would recommend sticking with MFC classes for such file I/O.
Sadly, I am using VS 2008, but here is the class hierarchy for CFile:
If it's a text file, using/deriving from CStdioFile makes sense. It has the basic ReadString WriteString methods.
However, if you are wanting to serialize something derived from CDocument (Document/View architecture), you will want to utilize streams, possibly with schemas/versioning to go with your serialization. That's a completely different topic/answer.
EDIT: duh - here's a simple CStdioFile output
CFileDialog fd(FALSE, "txt", "MyFile.txt", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "Text files (*.txt)|*.txt|All files (*.*)|*.*", this);
if (fd.DoModal() == IDOK)
{
CStdioFile fOut(fd.GetPathName(), CFile::modeCreate | CFile::modeWrite);
for (int i = 0; i < asData.GetSize(); i++)
{
fOut.WriteString(asData[i] + '\n');
}
fOut.Close();
}
Here is a very basic sample:
...
if (dlg.DoModal() == IDOK)
{
filename = dlg.GetPathName(); // return full path and filename
FILE *file = fopen(filename, "w"); // open file for writing
if (file == NULL)
AfxMessageBox("File couild not be created."};
else
{
// file could be created, write something
fprintf(file, "Some text\n");
// and close the file
fclose(file);
}
}
...
This will write "some text" into the file whose name has been provided by the user with the CFileDialog file picker.
In real world you need to write whatever text according to the data of your program.
This is really most basic knowledge.
I'm 100% new here, and I'm not sure if anything else is expected before I post this question. But I didn't find anything about this exact issue when searching, so here goes:
I have a Solution framework using Selenium ChromeDriver for automating a web site, and an included Unit Test project for running the tests.
The tests can be run fine from the VS Test Explorer. But when I try running them from the VS console with
MSTest.exe /testcontainer:d:\Source\Workspaces\QA\Automation\Tests\bin\Debug\Tests.dll /resultsfile:d:\QA\testresults\autotests\regressiontests\tests.trx
i get these errors in the results file:
Test method Tests.BasicTests.Data.GetSiteData.GetMyElementId threw exception:
System.Exception: File not found
at Bytescout.Spreadsheet.Spreadsheet.LoadFromFile(String FileName, CacheType Cache, String Delimiter, Encoding Encoding, String Password)
at Bytescout.Spreadsheet.Spreadsheet.LoadFromFile(String FileName)
at TestData.Readers.ExcelByteScout.ExcelFindRows(String url, String sheetname, String value, Int32 col) in d:\Source\Workspaces\QA\FlowAutomation\TestData\Readers\EscelByteScout.cs:line 113
at TestData.SiteData.MyElements.GetElementId(String location, String element) in d:\Source\Workspaces\QA\Automation\TestData\SiteData\MyElements.cs:line 27
at Tests.BasicTests.Data.GetSiteData.GetMyElementId() in d:\Source\Workspaces\QA\Automation\Tests\BasicTests\Data\GetSiteData.cs:line 13
This is complaining about a Project -> Class in the solution which reads test data (user logins, CSS elements...) from an excel file.
and
Initialization method Tests.TestTests.OpenTests.OpenMyLabDrop2.Init threw exception. OpenQA.Selenium.DriverServiceNotFoundException: OpenQA.Selenium.DriverServiceNotFoundException: The chromedriver.exe file does not exist in the current directory or in a directory on the PATH environment variable. The driver can be downloaded at http://chromedriver.storage.googleapis.com/index.html..
at OpenQA.Selenium.DriverService.FindDriverServiceExecutable(String executableName, Uri downloadUrl)
at OpenQA.Selenium.Chrome.ChromeDriverService.CreateDefaultService()
at Common.Selenium.GCDriver.Initialize() in d:\Source\Workspaces\QA\FlowAutomation\Common\Selenium\GCDriver.cs:line 19
at FlowTests.Base.MyLabDrop2Test.Init() in d:\Source\Workspaces\QA\FlowAutomation\FlowTests\Base\MyLabDrop2Test.cs:line 15
this complains about a missing ChromeDriver.exe which is definetely not missing.
I'm not COMPLETELY new to VS and Selenium, but this I don't get, since the tests run fine from VS but complain about missing references from the console.
So I'm pretty sure there's something I'm missing when running the tests from the console, but what?
EDIT:
The relevant code from ExceByteScout.cs:
using System;
using System.Collections.Generic;
using Bytescout.Spreadsheet;
namespace TestData.Readers {
public class ExcelByteScout {
public static List<string> ExcelReturnXYZ(string url, string sheetname, string cell1, string cell2, string cell3) {
Spreadsheet document = new Spreadsheet();
document.LoadFromFile(url);
Worksheet worksheet = document.Workbook.Worksheets.ByName(sheetname);
List<string> cellvalues = new List<string>();
string name = worksheet.Cell(cell1).Value.ToString();
string user = worksheet.Cell(cell2).Value.ToString();
string pass = worksheet.Cell(cell3).Value.ToString();
cellvalues.Add(name);
cellvalues.Add(user);
cellvalues.Add(pass);
document.Close();
return cellvalues;
}
public static string[] ExcelFindRows(string url, string sheetname, string value, int col) {
Spreadsheet document = new Spreadsheet();
Worksheet worksheet = null;
List<string> values = new List<string>();
string[] userdata = null;
try {
document.LoadFromFile(url);
}
catch (System.Exception ex) {
System.Diagnostics.Debug.WriteLine(ex.Message);
throw;
}
try {
worksheet = document.Workbook.Worksheets.ByName(sheetname);
}
catch (System.NullReferenceException nrex) {
System.Diagnostics.Debug.WriteLine(nrex.Message);
throw;
}
int i = 0;
while (!worksheet.Cell(i, col).ValueAsString.Equals("")) {
if (worksheet.Cell(i, col).ValueAsString.Equals(value)) {
int rowcellcount = 0;
for (int y = 0; !worksheet.Cell(i, y).ValueAsString.Equals(""); y++) {
rowcellcount++;
}
userdata = new string[rowcellcount];
for (int x = 0; x < rowcellcount; x++) {
userdata[x] = worksheet.Cell(i, x).ValueAsString;
}
break;
}
i++;
}
document.Close();
return userdata
}
UPDATE:
The FileNotFound problem was due to a relative path.
But the ChromeDriver not found issue is a mystery. Specifically because this has worked before, in a different solution but with the exact same way of running the tests from the console.
Also, I'm standing in the /Debug folder of the project when I run MSTest.exe, and chromedriver.exe IS in this folder. I cannot see where else it needs to be?
File not found usually means that the file is not found on the location you expect it to be. This can happen because you run from an other path or the file is not copied.
Check the url before the line document.LoadFromFile(url); by Console.WriteLine(url). Then copy the excel to the correct location or fix the url.
I want to use "GATE" through web. Then I decide to create a SOAP web service in java with help of GATE Embedded.
But for the same document and saved Pipeline, I have a different run-time duration, when GATE Embedded runs as a java web service.
The same code has a constant run-time when it runs as a Java Application project.
In the web service, the run-time will be increasing after each execution until I get a Timeout error.
Does any one have this kind of experience?
This is my Code:
#WebService(serviceName = "GateWS")
public class GateWS {
#WebMethod(operationName = "gateengineapi")
public String gateengineapi(#WebParam(name = "PipelineNumber") String PipelineNumber, #WebParam(name = "Documents") String Docs) throws Exception {
try {
System.setProperty("gate.home", "C:\\GATE\\");
System.setProperty("shell.path", "C:\\cygwin2\\bin\\sh.exe");
Gate.init();
File GateHome = Gate.getGateHome();
File FrenchGapp = new File(GateHome, PipelineNumber);
CorpusController FrenchController;
FrenchController = (CorpusController) PersistenceManager.loadObjectFromFile(FrenchGapp);
Corpus corpus = Factory.newCorpus("BatchProcessApp Corpus");
FrenchController.setCorpus(corpus);
File docFile = new File(GateHome, Docs);
Document doc = Factory.newDocument(docFile.toURL(), "utf-8");
corpus.add(doc);
FrenchController.execute();
String docXMLString = null;
docXMLString = doc.toXml();
String outputFileName = doc.getName() + ".out.xml";
File outputFile = new File(docFile.getParentFile(), outputFileName);
FileOutputStream fos = new FileOutputStream(outputFile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
OutputStreamWriter out;
out = new OutputStreamWriter(bos, "utf-8");
out.write(docXMLString);
out.close();
gate.Factory.deleteResource(doc);
return outputFileName;
} catch (Exception ex) {
return "ERROR: -> " + ex.getMessage();
}
}
}
I really appreciate any help you can provide.
The problem is that you're loading a new instance of the pipeline for every request, but then not freeing it again at the end of the request. GATE maintains a list internally of every PR/LR/controller that is loaded, so anything you load with Factory.createResource or PersistenceManager.loadObjectFrom... must be freed using Factory.deleteResource once it is no longer needed, typically using a try-finally:
FrenchController = (CorpusController) PersistenceManager.loadObjectFromFile(FrenchGapp);
try {
// ...
} finally {
Factory.deleteResource(FrenchController);
}
But...
Rather than loading a new instance of the pipeline every time, I would strongly recommend you explore a more efficient approach to load a smaller number of instances of the pipeline but keep them in memory to serve multiple requests. There is a fully worked-through example of this technique in the training materials on the GATE wiki, in particular module number 8 (track 2 Thursday).
I'm using log4cplus in my project to do logging.
I created logger.conf and I will load it in the beginning of my application.
This is my logger.conf:
log4cplus.appender.Developer=log4cplus::RollingFileAppender
log4cplus.appender.Developer.DatePattern = ".yyyy-MM-dd"
log4cplus.appender.Developer.Schedule = HOURLY
log4cplus.appender.Developer.File=log/developer.log
log4cplus.appender.Developer.MaxFileSize=3MB
log4cplus.appender.Developer.MaxBackupIndex=10
log4cplus.appender.Developer.layout=log4cplus::PatternLayout
log4cplus.appender.Developer.layout.ContextPrinting=enabled
log4cplus.appender.Developer.layout.ConversionPattern=%D{%Y-%m-%d %H:%M:%S,%Q} [%t] %p - %m%n
log4cplus.appender.Developer.Threshold=TRACE
log4cplus.logger.DEVELOPER=TRACE, Developer
This is how I load my logger.conf:
QString log_path = qApp->applicationDirPath() + "/log";
QDir().mkpath(log_path);
PropertyConfigurator logger(L"configs/logger.conf", Logger::getDefaultHierarchy());
logger.configure();
And whenever I want to log, I use the following line:
Logger::getInstance(L"DEVELOPER").log(INFO_LOG_LEVEL, L"..............");
I'd like to know two things:
How can I tell Log4Cplus to compress the backup logs?
In some post I saw this reply:
I need to create my own appender, inheriting from RollingFileAppender and then add a compression steps.
If it's possible, can anyone tell me how to do it, please? I don't know how to implement this.
How can I add a pattern to the name of these backup logs?
At the moment, Log4Cplus makes my back up like this:
developer.log.1
developer.log.2
developer.log.3
...
I'd like to add date and time to it.
You will need to implement you own Appender like this:
class NewFileAppender : public ::log4cplus::RollingFileAppender
{
void
newFileAppender::rollover()
{
helpers::LogLog & loglog = getLogLog();
// Close the current file
out.close();
out.clear(); // reset flags since the C++ standard specified that all the
// flags should remain unchanged on a close
// If maxBackups <= 0, then there is no file renaming to be done.
if (maxBackupIndex > 0)
{
rolloverCompressedFiles(filename, maxBackupIndex);
// Rename fileName to fileName.DATE
tstring target = filename + DATE;
int ret;
ret = file_rename (filename, target);
//TODO: compress using zlib
}
}
}