Skip to content

Instantly share code, notes, and snippets.

@adriannier
Last active September 3, 2015 09:49
Show Gist options
  • Save adriannier/4beeb28306869f7f37d5 to your computer and use it in GitHub Desktop.
Save adriannier/4beeb28306869f7f37d5 to your computer and use it in GitHub Desktop.
-- 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