Last active
September 3, 2015 09:49
-
-
Save adriannier/4beeb28306869f7f37d5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Create a new Log Manager instance | |
set LOGGER to newLogManager("~/Desktop/LogManagerTest.log") | |
tell LOGGER | |
-- Test by sending 30,000 messages; this should cause the auto archive feature to trigger | |
repeat 10000 times | |
infoLog("This is an informational message") | |
errorLog("This is an error") | |
debugLog("This is a debug message") | |
end repeat | |
end tell | |
on newLogManager(logFilePath) | |
script ANLogManager | |
(* | |
ANLogManager v1.0: | |
1. Create a new Log Manager instance using: | |
set LOGGER to newLogManager("~/Desktop/LogManagerTest.log") | |
The path can be an HFS path or POSIX path. The latter can also contain a tilde. | |
2. Send messages using one of the following functions: | |
infoLog("This is an informational message") -- No prefix | |
errorLog("This is an error") -- Message is prefixed with "[Error]" | |
debugLog("This is a debug message") -- Message is prefixed with "[Debug]" | |
Each message is also prefixed with a timestamp before it is written to disk. | |
Once the log file reaches or exceeds a size of 1 MB it will be | |
automatically archived. By default a maximum count of 100 | |
archives is kept. | |
*) | |
-- Log file name, its full path and the path to the parent folder | |
property LOG_FILE_NAME : "" | |
property LOG_FILE_PATH : "" | |
property PARENT_FOLDER_PATH : "" | |
-- Archiving parameters | |
property MAX_SIZE : 1000 * 1000 -- 1 MB | |
property MAX_ARCHIVE_COUNT : 100 | |
-- For performance, limit how many times file size is checked | |
property MESSAGES_SINCE_LAST_SIZE_CHECK : 100 -- Make sure file size is checked on first run | |
-- Time stamp caching, no need to regenerate it multiple times per second | |
property LAST_MESSAGE_DATE : false | |
property LAST_TIME_STAMP : false | |
on initWithPath(aPath) | |
-- Set file path property | |
set my LOG_FILE_PATH to convertToHFSPath(aPath) | |
-- Set the parent folder and file name properties | |
set prvDlmt to text item delimiters | |
set text item delimiters to ":" | |
set my PARENT_FOLDER_PATH to (text items 1 thru -2 of hfsPath() as text) & ":" | |
set my LOG_FILE_NAME to text item -1 of hfsPath() as text | |
set text item delimiters to prvDlmt | |
end initWithPath | |
on infoLog(msg) | |
set didArchive to archiveIfLargeEnough() | |
logMessage(msg, false, true, didArchive is false) | |
end infoLog | |
on errorLog(msg) | |
set didArchive to archiveIfLargeEnough() | |
logMessage(msg, "[Error] ", true, didArchive is false) | |
end errorLog | |
on debugLog(msg) | |
set didArchive to archiveIfLargeEnough() | |
logMessage(msg, "[Debug] ", true, didArchive is false) | |
end debugLog | |
on logMessage(msg, prefix, includeTimestamp, appending) | |
-- Add prefix | |
if prefix is not false then set msg to prefix & msg | |
-- Add time stamp | |
if includeTimestamp then set msg to timeStamp() & " " & msg | |
-- Write the prefixed message to disk | |
writeToDisk(msg, appending) | |
-- Raise the count since last size check | |
set my MESSAGES_SINCE_LAST_SIZE_CHECK to (my MESSAGES_SINCE_LAST_SIZE_CHECK) + 1 | |
return | |
end logMessage | |
on writeToDisk(msg, append) | |
try | |
set filePath to hfsPath() | |
-- Open file | |
try | |
open for access file filePath with write permission | |
on error eMsg number eNum | |
-- Error -49 means that the file is already open | |
if eNum is not -49 then | |
try | |
close access file filePath | |
end try | |
if eNum is -128 then error eMsg number eNum -- User cancelled | |
error "writeToDisk(): Could not open file with write permission: " & eMsg number eNum | |
end if | |
end try | |
-- Write to file | |
try | |
-- Determine end of file and data to write | |
set fileEnd to 0 | |
if append then | |
try | |
set fileEnd to (get eof of file filePath) + 1 | |
end try | |
end if | |
if fileEnd is 0 then set eof of file filePath to 0 | |
write msg & (ASCII character 10) to file filePath starting at fileEnd as Unicode text | |
on error eMsg number eNum | |
try | |
close access file filePath | |
end try | |
if eNum is -128 then error eMsg number eNum -- User cancelled | |
error "writeToDisk(): Error while writing to file: " & eMsg number eNum | |
end try | |
-- Close file | |
try | |
close access file filePath | |
end try | |
return | |
on error eMsg number eNum | |
try | |
close access file filePath | |
end try | |
return | |
if eNum is -128 then error eMsg number eNum -- User cancelled | |
error "writeToDisk(): " & eMsg number eNum | |
end try | |
end writeToDisk | |
on archiveIfLargeEnough() | |
-- Limit how many times the file size is checked | |
if my MESSAGES_SINCE_LAST_SIZE_CHECK is greater than or equal to 100 then | |
set my MESSAGES_SINCE_LAST_SIZE_CHECK to 0 | |
if logSize() is greater than or equal to my MAX_SIZE then return archive() | |
end if | |
return false | |
end archiveIfLargeEnough | |
on archive() | |
-- Compose a message to inform of archival | |
set turnOverMessage to "Log file turned over" | |
-- Add info to current log file | |
logMessage(turnOverMessage, false, true, true) | |
-- Archive log file | |
do shell script "/usr/bin/bzip2 -fk " & quotedPosixPath() | |
-- Delete oldest archive | |
set archivePathPrefix to parentFolderPath() & fileName() & "." | |
set oldestArchivePath to archivePathPrefix & stringForArchiveNumber(my MAX_ARCHIVE_COUNT) & ".bz2" | |
deleteFileAtPath(oldestArchivePath) | |
-- Rename archives (0.bz2 to 1.bz2, 1.bz2 to 2.bz2, etc.) | |
set archiveNumber to ((my MAX_ARCHIVE_COUNT) - 1) | |
repeat | |
set archivePath to archivePathPrefix & stringForArchiveNumber(archiveNumber) & ".bz2" | |
if fileExistsAtPath(archivePath) then | |
set newName to fileName() & "." & stringForArchiveNumber(archiveNumber + 1) & ".bz2" | |
renameFileAtHFSPath(archivePath, parentFolderPath(), newName) | |
end if | |
set archiveNumber to archiveNumber - 1 | |
if archiveNumber < 0 then exit repeat | |
end repeat | |
-- Rename newest archive | |
set archivePath to archivePathPrefix & "bz2" | |
set newName to fileName() & "." & stringForArchiveNumber(0) & ".bz2" | |
renameFileAtHFSPath(archivePath, parentFolderPath(), newName) | |
return true | |
end archive | |
on stringForArchiveNumber(aNum) | |
return pad(aNum as text, count of (my MAX_ARCHIVE_COUNT as text), "0") | |
end stringForArchiveNumber | |
on logSize() | |
try | |
set fileSize to size of (info for file hfsPath()) | |
return fileSize | |
on error | |
return 0 | |
end try | |
end logSize | |
on hfsPath() | |
return my LOG_FILE_PATH | |
end hfsPath | |
on quotedPosixPath() | |
return quoted form of (POSIX path of hfsPath()) | |
end quotedPosixPath | |
on fileName() | |
return my LOG_FILE_NAME | |
end fileName | |
on parentFolderPath() | |
return my PARENT_FOLDER_PATH | |
end parentFolderPath | |
on timeStamp() | |
-- Set the date | |
set aDate to current date | |
-- No need to generate time stamp again; simply return the cached one | |
if (my LAST_MESSAGE_DATE) is aDate then return (my LAST_TIME_STAMP) | |
-- Get the month and day as integer | |
set m to month of aDate as integer | |
set d to day of aDate | |
-- Get the year | |
set y to year of aDate as text | |
-- Get the seconds since midnight | |
set theTime to (time of aDate) | |
-- Get hours, minutes, and seconds | |
set h to theTime div (60 * 60) | |
set min to theTime mod (60 * 60) div 60 | |
set s to theTime mod 60 | |
-- Zeropad month value | |
set m to m as text | |
if (count of m) is less than 2 then set m to "0" & m | |
-- Zeropad day value | |
set d to d as text | |
if (count of d) is less than 2 then set d to "0" & d | |
-- Zeropad hours value | |
set h to h as text | |
if (count of h) is less than 2 then set h to "0" & h | |
-- Zeropad minutes value | |
set min to min as text | |
if (count of min) is less than 2 then set min to "0" & min | |
-- Zeropad seconds value | |
set s to s as text | |
if (count of s) is less than 2 then set s to "0" & s | |
set theTimeStamp to y & "-" & m & "-" & d & " " & h & ":" & min & ":" & s | |
set my LAST_MESSAGE_DATE to aDate | |
set my LAST_TIME_STAMP to theTimeStamp | |
return theTimeStamp | |
end timeStamp | |
on fileExistsAtPath(aPath) | |
-- Convert path to HFS style | |
set aPath to convertToHFSPath(aPath) | |
try | |
-- Get info for this file | |
set fileInfo to info for file aPath | |
on error eMsg number eNum | |
return false | |
end try | |
-- This is a folder! | |
if folder of fileInfo then return false | |
return true | |
end fileExistsAtPath | |
on deleteFileAtPath(aPath) | |
set aPath to convertToHFSPath(aPath) | |
-- Abort, if file does not exist | |
if fileExistsAtPath(aPath) is false then return | |
try | |
-- Give System Events a chance to delete the file | |
with timeout of 3 seconds | |
tell application "System Events" to delete file aPath | |
end timeout | |
on error | |
if fileExistsAtPath(aPath) then | |
do shell script "/bin/rm -f " & quoted form of (POSIX path of aPath) | |
if fileExistsAtPath(aPath) then error "Could not delete file at path " & POSIX path of aPath | |
end if | |
end try | |
end deleteFileAtPath | |
on renameFileAtHFSPath(hfsPath, hfsParentPath, newName) | |
if hfsParentPath does not end with ":" then set hfsParentPath to hfsParentPath & ":" | |
deleteFileAtPath(hfsParentPath) | |
try | |
tell application "System Events" | |
set name of file hfsPath to newName | |
end tell | |
on error eMsg number eNum | |
do shell script "/bin/mv " & quoted form of (POSIX path of hfsPath) & " " & quoted form of (POSIX path of (hfsParentPath & newName)) | |
end try | |
end renameFileAtHFSPath | |
on convertToHFSPath(filePath) | |
(* | |
Convert any non-relative path to an HFS path. Tilde in POSIX paths is allowed | |
*) | |
-- Expand tilde in filePath | |
if filePath starts with "~" then | |
-- Get the path to the user’s home folder | |
set userPath to POSIX path of (path to home folder) | |
-- Remove trailing slash | |
if userPath ends with "/" then set userPath to text 1 thru -2 of userPath as text | |
if filePath is "~" then | |
set filePath to userPath | |
else | |
set filePath to userPath & text 2 thru -1 of filePath as text | |
end if | |
end if | |
-- Exclude strings that neither have a colon or slash | |
if filePath does not contain ":" and filePath does not contain "/" then | |
error "convertToHFSPath(\"" & filePath & "\"): Invalid path" | |
end if | |
-- Exclude strings that have a slash put do not start with one; relative paths are not handled | |
if filePath contains "/" and filePath does not start with "/" then | |
error "convertToHFSPath(\"" & filePath & "\"): Invalid path" | |
end if | |
-- Convert to HFS style path if necessary | |
if filePath does not contain ":" then | |
set filePath to (POSIX file filePath) as text | |
end if | |
return filePath | |
end convertToHFSPath | |
on pad(aText, newWidth, aPrefix) | |
-- Pad text to new width | |
repeat newWidth - (count of aText) times | |
set aText to aPrefix & aText | |
end repeat | |
return aText | |
end pad | |
end script | |
tell ANLogManager to initWithPath(logFilePath) | |
return ANLogManager | |
end newLogManager |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment