Browse Source

Some clean-ups and additions to Logger and FileLogger classes. Added some logging to the Introjucer.

tags/2021-05-28
jules 12 years ago
parent
commit
e77d5b12ef
13 changed files with 223 additions and 143 deletions
  1. +2
    -1
      extras/Introjucer/Introjucer.jucer
  2. +1
    -1
      extras/Introjucer/JuceLibraryCode/AppConfig.h
  3. +57
    -0
      extras/Introjucer/Source/Application/jucer_Application.h
  4. +6
    -15
      extras/Introjucer/Source/Project Saving/jucer_ProjectSaver.h
  5. +3
    -2
      extras/Introjucer/Source/Project/jucer_Project.cpp
  6. +20
    -17
      extras/Introjucer/Source/Utility/jucer_StoredSettings.cpp
  7. +1
    -0
      extras/Introjucer/Source/Utility/jucer_StoredSettings.h
  8. +18
    -10
      modules/juce_core/files/juce_File.cpp
  9. +52
    -53
      modules/juce_core/logging/juce_FileLogger.cpp
  10. +47
    -19
      modules/juce_core/logging/juce_FileLogger.h
  11. +7
    -12
      modules/juce_core/logging/juce_Logger.cpp
  12. +3
    -7
      modules/juce_core/logging/juce_Logger.h
  13. +6
    -6
      modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp

+ 2
- 1
extras/Introjucer/Introjucer.jucer View File

@@ -244,7 +244,8 @@
JUCE_ALSA="disabled" JUCE_QUICKTIME="disabled" JUCE_OPENGL="disabled"
JUCE_USE_FLAC="disabled" JUCE_USE_CDBURNER="disabled" JUCE_USE_CDREADER="disabled"
JUCE_USE_CAMERA="disabled" JUCE_PLUGINHOST_VST="disabled" JUCE_PLUGINHOST_AU="disabled"
JUCE_USE_OGGVORBIS="disabled" JUCE_USE_COREIMAGE_LOADER="disabled"/>
JUCE_USE_OGGVORBIS="disabled" JUCE_USE_COREIMAGE_LOADER="disabled"
JUCE_LOG_ASSERTIONS="enabled"/>
<MODULES>
<MODULE id="juce_core" showAllCode="1"/>
<MODULE id="juce_events" showAllCode="1"/>


+ 1
- 1
extras/Introjucer/JuceLibraryCode/AppConfig.h View File

@@ -38,7 +38,7 @@
#endif
#ifndef JUCE_LOG_ASSERTIONS
//#define JUCE_LOG_ASSERTIONS
#define JUCE_LOG_ASSERTIONS 1
#endif
#ifndef JUCE_CHECK_MEMORY_LEAKS


+ 57
- 0
extras/Introjucer/Source/Application/jucer_Application.h View File

@@ -44,6 +44,8 @@ public:
//==============================================================================
void initialise (const String& commandLine)
{
initialiseLogger ("log_");
LookAndFeel::setDefaultLookAndFeel (&lookAndFeel);
settings = new StoredSettings();
settings->initialise();
@@ -116,6 +118,10 @@ public:
settings = nullptr;
LookAndFeel::setDefaultLookAndFeel (nullptr);
Logger::writeToLog ("Shutdown");
deleteLogger();
}
//==============================================================================
@@ -463,8 +469,57 @@ public:
}
//==============================================================================
void initialiseLogger (const char* filePrefix)
{
if (logger == nullptr)
{
logger = FileLogger::createDateStampedLogger (getLogFolderName(), filePrefix, ".txt",
getApplicationName() + " " + getApplicationVersion());
Logger::setCurrentLogger (logger);
}
}
void deleteLogger()
{
const int maxNumLogFilesToKeep = 50;
Logger::setCurrentLogger (nullptr);
if (logger != nullptr)
{
Array<File> logFiles;
logger->getLogFile().getParentDirectory().findChildFiles (logFiles, File::findFiles, false);
if (logFiles.size() > maxNumLogFilesToKeep)
{
struct FileWithTime
{
FileWithTime (const File& f) : file (f), time (f.getLastModificationTime()) {}
FileWithTime() {}
bool operator< (const FileWithTime& other) const { return time < other.time; }
bool operator== (const FileWithTime& other) const { return time == other.time; }
File file;
Time time;
};
Array <FileWithTime> files;
for (int i = 0; i < logFiles.size(); ++i)
files.addUsingDefaultSort (logFiles.getReference(i));
for (int i = 0; i < files.size() - maxNumLogFilesToKeep; ++i)
files.getReference(i).file.deleteFile();
}
}
logger = nullptr;
}
virtual void doExtraInitialisation() {}
virtual void addExtraConfigItems (Project&, TreeViewItem&) {}
virtual String getLogFolderName() const { return "com.juce.introjucer"; }
virtual Component* createProjectContentComponent() const
{
@@ -484,6 +539,8 @@ public:
ScopedPointer<Component> appearanceEditorWindow, utf8Window;
ScopedPointer<FileLogger> logger;
private:
class AsyncQuitRetrier : private Timer
{


+ 6
- 15
extras/Introjucer/Source/Project Saving/jucer_ProjectSaver.h View File

@@ -90,22 +90,13 @@ public:
project.createRequiredModules (moduleList, modules);
}
if (errors.size() == 0)
writeAppConfigFile (modules, appConfigUserContent);
if (errors.size() == 0) writeAppConfigFile (modules, appConfigUserContent);
if (errors.size() == 0) writeBinaryDataFiles();
if (errors.size() == 0) writeAppHeader (modules);
if (errors.size() == 0) writeProjects (modules);
if (errors.size() == 0) writeAppConfigFile (modules, appConfigUserContent); // (this is repeated in case the projects added anything to it)
if (errors.size() == 0)
writeBinaryDataFiles();
if (errors.size() == 0)
writeAppHeader (modules);
if (errors.size() == 0)
writeProjects (modules);
if (errors.size() == 0)
writeAppConfigFile (modules, appConfigUserContent); // (this is repeated in case the projects added anything to it)
if (generatedCodeFolder.exists() && errors.size() == 0)
if (errors.size() == 0 && generatedCodeFolder.exists())
writeReadmeFile();
if (generatedCodeFolder.exists())


+ 3
- 2
extras/Introjucer/Source/Project/jucer_Project.cpp View File

@@ -47,14 +47,15 @@ namespace Tags
const char* Project::projectFileExtension = ".jucer";
//==============================================================================
Project::Project (const File& file_)
Project::Project (const File& f)
: FileBasedDocument (projectFileExtension,
String ("*") + projectFileExtension,
"Choose a Jucer project to load",
"Save Jucer project"),
projectRoot (Tags::projectRoot)
{
setFile (file_);
Logger::writeToLog ("Loading project: " + f.getFullPathName());
setFile (f);
removeDefunctExporters();
setMissingDefaultValues();


+ 20
- 17
extras/Introjucer/Source/Utility/jucer_StoredSettings.cpp View File

@@ -90,31 +90,34 @@ PropertiesFile& StoredSettings::getProjectProperties (const String& projectUID)
return *p;
}
void StoredSettings::flush()
void StoredSettings::updateGlobalProps()
{
for (int i = propertyFiles.size(); --i >= 0;)
PropertiesFile& props = getGlobalProperties();
{
PropertiesFile* const props = propertyFiles.getUnchecked(i);
const ScopedPointer<XmlElement> xml (appearance.settings.createXml());
props.setValue ("editorColours", xml);
}
{
const ScopedPointer<XmlElement> xml (appearance.settings.createXml());
props->setValue ("editorColours", xml);
}
props.setValue ("recentFiles", recentFiles.toString());
props->setValue ("recentFiles", recentFiles.toString());
props.removeValue ("keyMappings");
props->removeValue ("keyMappings");
if (commandManager != nullptr)
{
const ScopedPointer <XmlElement> keys (commandManager->getKeyMappings()->createXml (true));
if (commandManager != nullptr)
{
ScopedPointer <XmlElement> keys (commandManager->getKeyMappings()->createXml (true));
if (keys != nullptr)
props.setValue ("keyMappings", keys);
}
}
if (keys != nullptr)
props->setValue ("keyMappings", (XmlElement*) keys);
}
void StoredSettings::flush()
{
updateGlobalProps();
props->saveIfNeeded();
}
for (int i = propertyFiles.size(); --i >= 0;)
propertyFiles.getUnchecked(i)->saveIfNeeded();
}
void StoredSettings::reload()


+ 1
- 0
extras/Introjucer/Source/Utility/jucer_StoredSettings.h View File

@@ -71,6 +71,7 @@ public:
private:
OwnedArray<PropertiesFile> propertyFiles;
void updateGlobalProps();
void loadSwatchColours();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StoredSettings);


+ 18
- 10
modules/juce_core/files/juce_File.cpp View File

@@ -130,21 +130,29 @@ String File::parseAbsolutePath (const String& p)
// expand a name of type "~dave/abc"
const String userName (path.substring (1).upToFirstOccurrenceOf ("/", false, false));
struct passwd* const pw = getpwnam (userName.toUTF8());
if (pw != nullptr)
if (struct passwd* const pw = getpwnam (userName.toUTF8()))
path = addTrailingSeparator (pw->pw_dir) + path.fromFirstOccurrenceOf ("/", false, false);
}
}
else if (! path.startsWithChar (separator))
{
/* When you supply a raw string to the File object constructor, it must be an absolute path.
If you're trying to parse a string that may be either a relative path or an absolute path,
you MUST provide a context against which the partial path can be evaluated - you can do
this by simply using File::getChildFile() instead of the File constructor. E.g. saying
"File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
path if that's what was supplied, or would evaluate a partial path relative to the CWD.
*/
jassert (path.startsWith ("./") || path.startsWith ("../")); // (assume that a path "./xyz" is deliberately intended to be relative to the CWD)
#if JUCE_DEBUG || JUCE_LOG_ASSERTIONS
if (! (path.startsWith ("./") || path.startsWith ("../")))
{
/* When you supply a raw string to the File object constructor, it must be an absolute path.
If you're trying to parse a string that may be either a relative path or an absolute path,
you MUST provide a context against which the partial path can be evaluated - you can do
this by simply using File::getChildFile() instead of the File constructor. E.g. saying
"File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
path if that's what was supplied, or would evaluate a partial path relative to the CWD.
*/
jassertfalse;
#if JUCE_LOG_ASSERTIONS
Logger::writeToLog ("Illegal absolute path: " + path);
#endif
}
#endif
return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName();
}


+ 52
- 53
modules/juce_core/logging/juce_FileLogger.cpp View File

@@ -23,19 +23,16 @@
==============================================================================
*/
FileLogger::FileLogger (const File& logFile_,
FileLogger::FileLogger (const File& file,
const String& welcomeMessage,
const int maxInitialFileSizeBytes)
: logFile (logFile_)
const int64 maxInitialFileSizeBytes)
: logFile (file)
{
if (maxInitialFileSizeBytes >= 0)
trimFileSize (maxInitialFileSizeBytes);
if (! logFile_.exists())
{
// do this so that the parent directories get created..
logFile_.create();
}
if (! file.exists())
file.create(); // (to create the parent directories)
String welcome;
welcome << newLine
@@ -46,23 +43,18 @@ FileLogger::FileLogger (const File& logFile_,
FileLogger::logMessage (welcome);
}
FileLogger::~FileLogger()
{
}
FileLogger::~FileLogger() {}
//==============================================================================
void FileLogger::logMessage (const String& message)
{
DBG (message);
const ScopedLock sl (logLock);
DBG (message);
FileOutputStream out (logFile, 256);
out << message << newLine;
}
void FileLogger::trimFileSize (int maxFileSizeBytes) const
void FileLogger::trimFileSize (int64 maxFileSizeBytes) const
{
if (maxFileSizeBytes <= 0)
{
@@ -74,59 +66,66 @@ void FileLogger::trimFileSize (int maxFileSizeBytes) const
if (fileSize > maxFileSizeBytes)
{
ScopedPointer <FileInputStream> in (logFile.createInputStream());
jassert (in != nullptr);
TemporaryFile tempFile (logFile);
if (in != nullptr)
{
in->setPosition (fileSize - maxFileSizeBytes);
String content;
FileOutputStream out (tempFile.getFile());
FileInputStream in (logFile);
{
MemoryBlock contentToSave;
contentToSave.setSize ((size_t) maxFileSizeBytes + 4);
contentToSave.fillWith (0);
if (! (out.openedOk() && in.openedOk()))
return;
in->read (contentToSave.getData(), maxFileSizeBytes);
in = nullptr;
in.setPosition (fileSize - maxFileSizeBytes);
content = contentToSave.toString();
for (;;)
{
const char c = in.readByte();
if (c == 0)
return;
if (c == '\n' || c == '\r')
{
out << c;
break;
}
}
int newStart = 0;
while (newStart < fileSize
&& content[newStart] != '\n'
&& content[newStart] != '\r')
++newStart;
logFile.deleteFile();
logFile.appendText (content.substring (newStart), false, false);
out.writeFromInputStream (in, -1);
}
tempFile.overwriteTargetFileWithTemporary();
}
}
}
//==============================================================================
FileLogger* FileLogger::createDefaultAppLogger (const String& logFileSubDirectoryName,
const String& logFileName,
const String& welcomeMessage,
const int maxInitialFileSizeBytes)
File FileLogger::getSystemLogFileFolder()
{
#if JUCE_MAC
File logFile ("~/Library/Logs");
logFile = logFile.getChildFile (logFileSubDirectoryName)
.getChildFile (logFileName);
return File ("~/Library/Logs");
#else
File logFile (File::getSpecialLocation (File::userApplicationDataDirectory));
if (logFile.isDirectory())
{
logFile = logFile.getChildFile (logFileSubDirectoryName)
.getChildFile (logFileName);
}
return File::getSpecialLocation (File::userApplicationDataDirectory);
#endif
}
return new FileLogger (logFile, welcomeMessage, maxInitialFileSizeBytes);
FileLogger* FileLogger::createDefaultAppLogger (const String& logFileSubDirectoryName,
const String& logFileName,
const String& welcomeMessage,
const int64 maxInitialFileSizeBytes)
{
return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
.getChildFile (logFileName),
welcomeMessage, maxInitialFileSizeBytes);
}
FileLogger* FileLogger::createDateStampedLogger (const String& logFileSubDirectoryName,
const String& logFileNameRoot,
const String& logFileNameSuffix,
const String& welcomeMessage)
{
return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
.getChildFile (logFileNameRoot + Time::getCurrentTime().formatted ("%Y-%m-%d_%H-%M-%S"))
.withFileExtension (logFileNameSuffix)
.getNonexistentSibling(),
welcomeMessage, 0);
}

+ 47
- 19
modules/juce_core/logging/juce_FileLogger.h View File

@@ -59,47 +59,75 @@ public:
*/
FileLogger (const File& fileToWriteTo,
const String& welcomeMessage,
const int maxInitialFileSizeBytes = 128 * 1024);
const int64 maxInitialFileSizeBytes = 128 * 1024);
/** Destructor. */
~FileLogger();
//==============================================================================
void logMessage (const String& message);
File getLogFile() const { return logFile; }
/** Returns the file that this logger is writing to. */
const File& getLogFile() const noexcept { return logFile; }
//==============================================================================
/** Helper function to create a log file in the correct place for this platform.
On Windows this will return a logger with a path such as:
c:\\Documents and Settings\\username\\Application Data\\[logFileSubDirectoryName]\\[logFileName]
On the Mac it'll create something like:
~/Library/Logs/[logFileName]
The method might return 0 if the file can't be created for some reason.
The method might return nullptr if the file can't be created for some reason.
@param logFileSubDirectoryName if a subdirectory is needed, this is what it will be called -
it's best to use the something like the name of your application here.
@param logFileName the name of the file to create, e.g. "MyAppLog.txt". Don't just
call it "log.txt" because if it goes in a directory with logs
from other applications (as it will do on the Mac) then no-one
will know which one is yours!
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
returned by getSystemLogFileFolder). It's best to use something
like the name of your application here.
@param logFileName the name of the file to create, e.g. "MyAppLog.txt".
@param welcomeMessage a message that will be written to the log when it's opened.
@param maxInitialFileSizeBytes (see the FileLogger constructor for more info on this)
*/
static FileLogger* createDefaultAppLogger (const String& logFileSubDirectoryName,
const String& logFileName,
const String& welcomeMessage,
const int maxInitialFileSizeBytes = 128 * 1024);
const int64 maxInitialFileSizeBytes = 128 * 1024);
/** Helper function to create a log file in the correct place for this platform.
The filename used is based on the root and suffix strings provided, along with a
time and date string, meaning that a new, empty log file will be always be created
rather than appending to an exising one.
The method might return nullptr if the file can't be created for some reason.
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
returned by getSystemLogFileFolder). It's best to use something
like the name of your application here.
@param logFileNameRoot the start of the filename to use, e.g. "MyAppLog_". This will have
a timestamp and the logFileNameSuffix appended to it
@param logFileNameSuffix the file suffix to use, e.g. ".txt"
@param welcomeMessage a message that will be written to the log when it's opened.
*/
static FileLogger* createDateStampedLogger (const String& logFileSubDirectoryName,
const String& logFileNameRoot,
const String& logFileNameSuffix,
const String& welcomeMessage);
//==============================================================================
/** Returns an OS-specific folder where log-files should be stored.
On Windows this will return a logger with a path such as:
c:\\Documents and Settings\\username\\Application Data\\[logFileSubDirectoryName]\\[logFileName]
On the Mac it'll create something like:
~/Library/Logs/[logFileSubDirectoryName]/[logFileName]
@see createDefaultAppLogger
*/
static File getSystemLogFileFolder();
// (implementation of the Logger virtual method)
void logMessage (const String&);
private:
//==============================================================================
File logFile;
CriticalSection logLock;
void trimFileSize (int maxFileSizeBytes) const;
void trimFileSize (int64 maxFileSizeBytes) const;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileLogger);
};


+ 7
- 12
modules/juce_core/logging/juce_Logger.cpp View File

@@ -23,25 +23,20 @@
==============================================================================
*/
Logger::Logger()
{
}
Logger::Logger() {}
Logger::~Logger()
{
// You're deleting this logger while it's still being used!
// Always call Logger::setCurrentLogger (nullptr) before deleting the active logger.
jassert (currentLogger != this);
}
//==============================================================================
Logger* Logger::currentLogger = nullptr;
void Logger::setCurrentLogger (Logger* const newLogger,
const bool deleteOldLogger)
void Logger::setCurrentLogger (Logger* const newLogger) noexcept
{
Logger* const oldLogger = currentLogger;
currentLogger = newLogger;
if (deleteOldLogger)
delete oldLogger;
}
void Logger::writeToLog (const String& message)
@@ -53,10 +48,10 @@ void Logger::writeToLog (const String& message)
}
#if JUCE_LOG_ASSERTIONS
void JUCE_API logAssertion (const char* filename, const int lineNum) noexcept
void JUCE_API logAssertion (const char* const filename, const int lineNum) noexcept
{
String m ("JUCE Assertion failure in ");
m << filename << ", line " << lineNum;
m << File (filename).getFileName() << ':' << lineNum;
Logger::writeToLog (m);
}


+ 3
- 7
modules/juce_core/logging/juce_Logger.h View File

@@ -51,14 +51,11 @@ public:
//==============================================================================
/** Sets the current logging class to use.
Note that the object passed in won't be deleted when no longer needed.
Note that the object passed in will not be owned or deleted by the logger, so
the caller must make sure that it is not deleted while still being used.
A null pointer can be passed-in to disable any logging.
If deleteOldLogger is set to true, the existing logger will be
deleted (if there is one).
*/
static void JUCE_CALLTYPE setCurrentLogger (Logger* newLogger,
bool deleteOldLogger = false);
static void JUCE_CALLTYPE setCurrentLogger (Logger* newLogger) noexcept;
/** Writes a string to the current logger.
@@ -84,7 +81,6 @@ protected:
Logger();
/** This is overloaded by subclasses to implement custom logging behaviour.
@see setCurrentLogger
*/
virtual void logMessage (const String& message) = 0;


+ 6
- 6
modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp View File

@@ -103,17 +103,17 @@ File PropertiesFile::Options::getDefaultFile() const
//==============================================================================
PropertiesFile::PropertiesFile (const File& file_, const Options& options_)
: PropertySet (options_.ignoreCaseOfKeyNames),
file (file_), options (options_),
PropertiesFile::PropertiesFile (const File& f, const Options& o)
: PropertySet (o.ignoreCaseOfKeyNames),
file (f), options (o),
loadedOk (false), needsWriting (false)
{
initialise();
}
PropertiesFile::PropertiesFile (const Options& options_)
: PropertySet (options_.ignoreCaseOfKeyNames),
file (options_.getDefaultFile()), options (options_),
PropertiesFile::PropertiesFile (const Options& o)
: PropertySet (o.ignoreCaseOfKeyNames),
file (o.getDefaultFile()), options (o),
loadedOk (false), needsWriting (false)
{
initialise();


Loading…
Cancel
Save