Logging with a smile 😃

TrevorProductivity, Scripting, TipsLeave a Comment

The ability to see snapshots of a script progress throughout it's execution is crucial for the writing and debugging of complex scripts. There are scripters who are dependent on using the ESTK for developing scripts for the most of Adobe's well know products like InDesign, Illustrator, Photoshop, Premier Pro and After Effects to name but a few. What they do not appreciate is the degree of handicap they are inflicting on themselves because of their dependency. I'll probably discus this topic in the future, don't get me wrong I'm not saying that there is no place for using the ESTK just that it should be used cautiously as an exception. I want to show that the use of the ESTK for the purpose of writing to the console is a bad idea.

OK for your little 20 line snippet it's not necessarily exactly the end of the world, but one has to know that writing to the ESTK console is really incredibly slow, it's comes out pretty illegible, trying to find one entry amongst a multitude of other is no pleasure to put it mildly. There's no keeping of the output from session to session and there's no built in search and find for the console. The use of the alert function has obvious problems, again I'm not saying there's no place for it just that it's very lacking.

An effective well known and well practiced solution is logging. There are many logging API's, I wrote this one to for Adobe JSX scripts to suit my needs. It's very quick, easy to use, produces easy to read and informative logs and has an extensive API. A minor feature of the API is the use of emojis for emphasizing individual log entries so they can be found and categorized quickly, perhaps the implementation here is a bit of an overkill and it would be better to remove a lot of the available emojis.

💾 The Squished Script:

LogFactory.squished.jsx CopyRawDownload

NOTE: For all the snippets below and for general usage of the API either paste the above 2 lines or the verbose 949 line version to the beginning of your code or include it by using the #include directive.
The full API is explained below and the full readable LogFactory.jsx script can be found at the end of the post.

Included Features:
Leveled logging (See below for the meaning of this if you don't know) 👀
Writing and reading level cookies so the log level can be changed without changing the script 👀
Multiple instances of log files 👀
Writing the log to the computers memory and extracting entry ranges of the log 👀
Methods for logging all the arguments of a function and values of variables 👀
A method for logging new objects created as per the $.summary() result 👀
A method for showing the call stack 👀
Different timing methods 👀
🐥 Most importantly easily and quickly produces clear numbered logs with their status and time stamp 👀
And last and least emoji's 🤓

Note:
🤐 The script is made for use on almost all of Adobe's scriptable applications (Acrobat being a noticeable exception) which run extended script. It will not function as is from the js side of an extension, changing the file functions here to work in an extension and or NodeJS environment should be a very simple task. If there's enough demand, maybe I'll do it.
🤐 The script could have been written more efficiently if it was written on a ProtoType bases, I did not do this as I wanted to just be able to add logs using the simple command log('foo'); and not something like console.log('foo');. O.k. I know I could have got around that easily using other methods like function log(){return console.log(arguments);} but the method as it is handles thousands of logs per second and is not going to blow the systems memory so there you have it. I have a simple NodeJS version that can easily vomit 100,000 logs per second, but 10,000 / second should cover most needs.

Snippet

Log Produced

[1] [INFO] 😃Hello [Sun Mar 05 2017 09:57:23 GMT+0200 332ms] [2] [ERROR] Drat [Sun Mar 05 2017 09:57:23 GMT+0200 332ms] [3] [IMPORTANT] 👉42 [Sun Mar 05 2017 09:57:23 GMT+0200 332ms] [4] [LOG] bye [Sun Mar 05 2017 09:57:23 GMT+0200 332ms]

Quick Links
LogFactory.jsx, 💾 DOWNLOAD, 🗜Download Squished Version, LOG, Log Methods, Log Properties, args(), close(), cookie(), execute(), file(), get(), openFolder(), reset(), setCount(), setFile(), setLevel(), setStatus(), show(), stack(), start(), stop(), stopper(), sumDiff(), values()

LogFactory.jsx API For easy creation of leveled logs

LogFactory(file, write, store, level, status, continuing)
The LogFactory function is used for the creation of the log factory. It returns the LOG function, the LOG function has different arguments than the LogFactory function they are explained below.
PARAMETER TYPE DESCRIPTION
file String or File Object Accepts either the File Object or a String of the full path to the log or just the file name of the log in which case it will be place in the systems temporary folder.
[Optional – default: If a path was previously set then that path will be used otherwise the log file will be created in the temporary folder and called LOG_Script Name_Year_Month_Date.log for example LOG_Script2_2017_Feb_21.log]. See the note to the log.setFile() method.
write Boolean If to write the logs to disk [Optional – default: true]. See the note to the log.setFile() method.
store Boolean If to store the logs in the computers memory [Optional – default: false]. See the note to the log.get() method.
level String or Integer The level from which to record the log [Optional – default: 2]. See the log.setLevel() method.
status String The default log status [Optional – default: LOG]. See the log.setLevel() and log.setStatus() methods.
continuing Boolean If the log count should continue from the last count in an existing file [Optional – default: false]. See the note to the log.setCount() method.
RETURNS Function The created LOG factory function
NOTES The LogFactory function should always be preceded with the new word i.e. var log = new LogFactory();

Snippet

LOG(message, status, icon)
After instantiating the log factory one has access to the LOG function. All methods and properties used in managing the log output after its creation are via the LOG function.
PARAMETER TYPE DESCRIPTION
message All Types The message to be sent to the log.
If no argument is placed in the log function then no logging will occur, however if undefined is passed then the string undefined will be logged. Any type of value can be passed, see the examples below.
status String The status to give the entry. Different statuses are assigned different log levels, this point is explained in the log level section below. Any string may be use, recognized statuses may be referred to with the abbreviations listed below. The statuses and their abbreviations are not case sensitive and will always be outputted in uppercase. Only entries matching or greater than the logging level will be added.
Level 0 – Custom statuses
Level 1 – RE: 'RESULT', ST: 'STOPPER', TI: 'TIMER', T: 'TRACE'
Level 2 – D: 'DEBUG', L: 'LOG', CO: 'CONSTANT', F: 'FUNCTION', R: 'RETURN', V: 'VARIABLE', S: 'STACK'
Level 3 – I: 'INFO', IM: 'IMPORTANT'
Level 4 – W: 'WARNING'
Level 5 – B: 'BUG', C: 'CRITICAL', E: 'ERROR'
Level 6 – FA: 'FATAL'
[Optional – default: the set default status – "LOG" if default status was not set]
icon String The icon to precede the message [Optional – default: no icon] Recognized icons:
1: 🕐, 130: 🕜, 2: 🕑, 230: 🕝, 3: 🕒, 330: 🕞, 4: 🕓, 430: 🕟, 5: 🕔, 530: 🕠, 6: 🕕, 630: 🕡, 7: 🕖, 730: 🕢, 8: 🕗, 830: 🕣, 9: 🕘, 930: 🕤, 10: 🕙, 1030: 🕥, 11: 🕚, 1130: 🕦, 12: 🕛, 1230: 🕧, AIRPLANE: 🛩, ALARM: ⏰, AMBULANCE: 🚑, ANCHOR: ⚓, ANGRY: 😠, ANGUISHED: 😧, ANT: 🐜, ANTENNA: 📡, APPLE: 🍏, APPLE2: 🍎, ATM: 🏧, ATOM: ⚛, BABYBOTTLE: 🍼, BAD: 👎, BANANA: 🍌, BANDAGE: 🤕, BANK: 🏦, BATTERY: 🔋, BED: 🛏, BEE: 🐝, BEER: 🍺, BELL: 🔔, BELLOFF: 🔕, BIRD: 🐦, BLACKFLAG: 🏴, BLUSH: 😊, BOMB: 💣, BOOK: 📕, BOOKMARK: 🔖, BOOKS: 📚, BOW: 🏹, BOWLING: 🎳, BRIEFCASE: 💼, BROKEN: 💔, BUG: 🐛, BUILDING: 🏛, BUILDINGS: 🏘, BULB: 💡, BUS: 🚌, CACTUS: 🌵, CALENDAR: 📅, CAMEL: 🐪, CAMERA: 📷, CANDLE: 🕯, CAR: 🚘, CAROUSEL: 🎠, CASTLE: 🏰, CATEYES: 😻, CATJOY: 😹, CATMOUTH: 😺, CATSMILE: 😼, CD: 💿, CHECK: ✔, CHEQFLAG: 🏁, CHICK: 🐥, CHICKEN: 🐔, CHICKHEAD: 🐤, CIRCLEBLACK: ⚫, CIRCLEBLUE: 🔵, CIRCLERED: 🔴, CIRCLEWHITE: ⚪, CIRCUS: 🎪, CLAPPER: 🎬, CLAPPING: 👏, CLIP: 📎, CLIPBOARD: 📋, CLOUD: 🌨, CLOVER: 🍀, CLOWN: 🤡, COLDSWEAT: 😓, COLDSWEAT2: 😰, COMPRESS: 🗜, CONFOUNDED: 😖, CONFUSED: 😕, CONSTRUCTION: 🚧, CONTROL: 🎛, COOKIE: 🍪, COOKING: 🍳, COOL: 😎, COOLBOX: 🆒, COPYRIGHT: ©, CRANE: 🏗, CRAYON: 🖍, CREDITCARD: 💳, CROSS: ✖, CROSSBOX: ❎, CRY: 😢, CRY2: 😥, CRYCAT: 😿, CRYSTALBALL: 🔮, CUSTOMS: 🛃, DELICIOUS: 😋, DERELICT: 🏚, DESKTOP: 🖥, DIAMONDLB: 🔷, DIAMONDLO: 🔶, DIAMONDSB: 🔹, DIAMONDSO: 🔸, DICE: 🎲, DISAPPOINTED: 😞, DIVISION: ➗, DIZZY: 😵, DOLLAR: 💵, DOLLAR2: 💲, DOWNARROW: ⬇, DVD: 📀, EJECT: ⏏, ELEPHANT: 🐘, EMAIL: 📧, ENVELOPE: 📨, ENVELOPE2: ✉, ENVELOPE_DOWN: 📩, EURO: 💶, EVIL: 😈, EXPRESSIONLESS: 😑, EYES: 👀, FACTORY: 🏭, FAX: 📠, FEARFUL: 😨, FILEBOX: 🗃, FILECABINET: 🗄, FIRE: 🔥, FIREENGINE: 🚒, FIST: 👊, FLOWER: 🌷, FLOWER2: 🌸, FLUSHED: 😳, FOLDER: 📁, FOLDER2: 📂, FREE: 🆓, FROG: 🐸, FROWN: 🙁, GEAR: ⚙, GLOBE: 🌍, GLOWINGSTAR: 🌟, GOOD: 👍, GRIMACING: 😬, GRIN: 😀, GRINNINGCAT: 😸, HALO: 😇, HAMMER: 🔨, HAMSTER: 🐹, HAND: ✋, HANDDOWN: 👇, HANDLEFT: 👈, HANDRIGHT: 👉, HANDUP: 👆, HATCHING: 🐣, HAZARD: ☣, HEADPHONE: 🎧, HEARNOEVIL: 🙉, HEARTBLUE: 💙, HEARTEYES: 😍, HEARTGREEN: 💚, HEARTYELLOW: 💛, HELICOPTER: 🚁, HERB: 🌿, HIGH_BRIGHTNESS: 🔆, HIGHVOLTAGE: ⚡, HIT: 🎯, HONEY: 🍯, HOT: 🌶, HOURGLASS: ⏳, HOUSE: 🏠, HUGGINGFACE: 🤗, HUNDRED: 💯, HUSHED: 😯, ID: 🆔, INBOX: 📥, INDEX: 🗂, JOY: 😂, KEY: 🔑, KISS: 😘, KISS2: 😗, KISS3: 😙, KISS4: 😚, KISSINGCAT: 😽, KNIFE: 🔪, LABEL: 🏷, LADYBIRD: 🐞, LANDING: 🛬, LAPTOP: 💻, LEFTARROW: ⬅, LEMON: 🍋, LIGHTNINGCLOUD: 🌩, LINK: 🔗, LITTER: 🚮, LOCK: 🔒, LOLLIPOP: 🍭, LOUDSPEAKER: 📢, LOW_BRIGHTNESS: 🔅, MAD: 😜, MAGNIFYING_GLASS: 🔍, MASK: 😷, MEDAL: 🎖, MEMO: 📝, MIC: 🎤, MICROSCOPE: 🔬, MINUS: ➖, MOBILE: 📱, MONEY: 💰, MONEYMOUTH: 🤑, MONKEY: 🐵, MOUSE: 🐭, MOUSE2: 🐁, MOUTHLESS: 😶, MOVIE: 🎥, MUGS: 🍻, NERD: 🤓, NEUTRAL: 😐, NEW: 🆕, NOENTRY: 🚫, NOTEBOOK: 📔, NOTEPAD: 🗒, NUTANDBOLT: 🔩, O: ⭕, OFFICE: 🏢, OK: 🆗, OKHAND: 👌, OLDKEY: 🗝, OPENLOCK: 🔓, OPENMOUTH: 😮, OUTBOX: 📤, PACKAGE: 📦, PAGE: 📄, PAINTBRUSH: 🖌, PALETTE: 🎨, PANDA: 🐼, PASSPORT: 🛂, PAWS: 🐾, PEN: 🖊, PEN2: 🖋, PENSIVE: 😔, PERFORMING: 🎭, PILL: 💊, PING: ❗, PLATE: 🍽, PLUG: 🔌, PLUS: ➕, POLICE: 🚓, POLICELIGHT: 🚨, POSTOFFICE: 🏤, POUND: 💷, POUTING: 😡, POUTINGCAT: 😾, PRESENT: 🎁, PRINTER: 🖨, PROJECTOR: 📽, PUSHPIN: 📌, QUESTION: ❓, RABBIT: 🐰, RADIOACTIVE: ☢, RADIOBUTTON: 🔘, RAINCLOUD: 🌧, RAT: 🐀, RECYCLE: ♻, REGISTERED: ®, RELIEVED: 😌, ROBOT: 🤖, ROCKET: 🚀, ROLLING: 🙄, ROOSTER: 🐓, RULER: 📏, SATELLITE: 🛰, SAVE: 💾, SCHOOL: 🏫, SCISSORS: ✂, SCREAMING: 😱, SCROLL: 📜, SEAT: 💺, SEEDLING: 🌱, SEENOEVIL: 🙈, SHIELD: 🛡, SHIP: 🚢, SHOCKED: 😲, SHOWER: 🚿, SLEEPING: 😴, SLEEPY: 😪, SLIDER: 🎚, SLOT: 🎰, SMILE: 🙂, SMILING: 😃, SMILINGCLOSEDEYES: 😆, SMILINGEYES: 😄, SMILINGSWEAT: 😅, SMIRK: 😏, SNAIL: 🐌, SNAKE: 🐍, SOCCER: ⚽, SOS: 🆘, SPEAKER: 🔈, SPEAKEROFF: 🔇, SPEAKNOEVIL: 🙊, SPIDER: 🕷, SPIDERWEB: 🕸, STAR: ⭐, STOP: ⛔, STOPWATCH: ⏱, SULK: 😦, SUNFLOWER: 🌻, SUNGLASSES: 🕶, SYRINGE: 💉, TAKEOFF: 🛫, TAXI: 🚕, PHONE: 📞, TELESCOPE: 🔭, TEMPORATURE: 🤒, TENNIS: 🎾, THERMOMETER: 🌡, THINKING: 🤔, THUNDERCLOUD: ⛈, TICKBOX: ✅, TICKET: 🎟, TIRED: 😫, TOILET: 🚽, TOMATO: 🍅, TONGUE: 😛, TOOLS: 🛠, TORCH: 🔦, TORNADO: 🌪, TOUNG2: 😝, TRADEMARK: ™, TRAFFICLIGHT: 🚦, TRASH: 🗑, TREE: 🌲, TRIANGLE_LEFT: ◀, TRIANGLE_RIGHT: ▶, TRIANGLEDOWN: 🔻, TRIANGLEUP: 🔺, TRIANGULARFLAG: 🚩, TROPHY: 🏆, TRUCK: 🚚, TRUMPET: 🎺, TURKEY: 🦃, TURTLE: 🐢, UMBRELLA: ⛱, UNAMUSED: 😒, UPARROW: ⬆, UPSIDEDOWN: 🙃, WARNING: ⚠, WATCH: ⌚, WAVING: 👋, WEARY: 😩, WEARYCAT: 🙀, WHITEFLAG: 🏳, WINEGLASS: 🍷, WINK: 😉, WORRIED: 😟, WRENCH: 🔧, X: ❌, YEN: 💴, ZIPPERFACE: 🤐
RETURNS String The created log entry
NOTES The LogFactory function will only be used once at the creation of the factory. After it's creation only the LOG function is used. The reference to the LOG method will be the name of variable used for the creation of the new log factory. Our examples are based on var log = new LogFactory();
The log output will be in the form of.
[1] [INFO] 💰Payment received [Sun Mar 05 2017 10:05:02 GMT+0200 562ms]
[Line number] [Status] (icon)message [Day Month Date Year Hours:Minutes:Seconds Time zone ms]

Examples

Log Produced

[1] [LOG] undefined [Fri Feb 24 2017 00:19:29 GMT+0200 162ms] [2] [LOG] Hello [Fri Feb 24 2017 00:19:29 GMT+0200 163ms] [3] [FATAL] Death [Fri Feb 24 2017 00:19:29 GMT+0200 164ms] [4] [INFO] 💰Payment received [Fri Feb 24 2017 00:19:29 GMT+0200 165ms]


LOG METHODS

METHOD DESCRIPTION
setLevel Sets the level from which the logs should be logged. This can also be set at the creation of the log factory using the level parameter of the LogFactory function.
cookie For reading and writing log level cookies for for the setting of the log level.
setStatus For setting the default log status. This can also be set at the creation of the log factory using the status parameter of the LogFactory function.
setFile For setting file were the log will be written to. This can also be set at the creation of the log factory using the file parameter of the LogFactory function.
get For retrieving individual or ranges of log entries. This will only work if the store parameter of the LogFactory function or the log.store argument are set to true
args Logs information about a function and it's augments. This is a nice method and worth looking at even if the rest of the post doesn't interest you
values Logs the values of an object or array.
sumDiff Shows the difference between $.summary() calls. Cheers Dirk 🍺
stack Logs the call stack.
file Returns the log file object (if there is one).
execute Opens the log file with the systems default application for opening the files with the suffix you have allocated to the log.
show This method is exactly the same as the show execute.
openFolder Opens the log folder containing the log file with Finder or Windows Explorer.
close Closes the log file.
setCount Sets the log count for the next log entry.
reset Resets the log factory to more or less it's default settings.
stopper For timing between 2 points.
start Registers a start point that will be matched by a pairing log.stop() call for timing purposes.
stop Logs timing information from a matching start point created using log.start().
NOTES Click the method to jump to it.


LOG PROPERTIES

PROPERTY TYPE DESCRIPTION
count Integer The count of the next log entry.
See also the log.setCount() method.
level Integer Sets the minimum log level from which logs are processed
It is normally recommended to set the value either on creating the new LogFactory using log = new LogFactory({level: 'DEBUG'}); or the log.setLevel() and log.cookie() methods all of which accept Strings and not just Integers which are the only valid type that the log.level accepts. See below "Log Levels and Statuses"
status String The default log status.
Can be set on creating the new LogFactory using log = new LogFactory({status: 'ERROR'}); or by using the log.setStatus() methods.
store Boolean If to store the logs in the computers memory
Can be set on creating the new LogFactory using log = new LogFactory({store: true});
See the log.get() method for the purpose of doing this.
write Boolean If to write the logs to disk
Can be set on creating the new LogFactory using log = new LogFactory({write: false});


Log Levels and Statuses
Each status has an associated log level assigned to it, these are listed below, by changing the log level one can filter out which log entries will be processed. You might while developing a script want to set the log level to log all debug logs and when done with debugging change the log level to error of fatal so only those levels will be logged.
The logging level can either be set on the creation of the log factory or by using the log.setLevel() method or by directly setting the log.level value.

log.setLevel(level)
Sets the level from which the logs should be logged.
PARAMETER TYPE DESCRIPTION
level String or Integer The level from which the logs should be logged. Any of the below values may be used, they are not case-sensitive. Each row of levels
0, ALL, YES, YEP, TRUE
1, TRACE, RESULT, STOPPER, TIMER, tr, re, st, ti, t
2, DEBUG, LOG, STACK, CONSTANT, FUNCTION, VARIABLE, RETURN, d, l, co, f, r, v, s
3, INFO, IMPORTANT, ON, i, im
4, WARN, WARNING, w
5, ERROR, BUG, CRITICAL, e, b, c
6, FATAL, FA
7, NONE, OFF, NONE, NOPE, FALSE
[Optional – default: 2]
RETURNS Integer The level from which the logs should be logged
NOTES Log entries whose status is equal or higher than the set level will be logged.
The log level can be also set at the creation of the log factory var log = new LogFactory({level: 'info'}) or by setting the level directly log.level = 3; if the level is set directly only integer values are valid.
[1] [CRITICAL] System's over heating [Sun Mar 05 2017 10:05:02 GMT+0200 562ms] [2] [FATAL] 🔥System's caught fire [Sun Mar 05 2017 10:05:02 GMT+0200 562ms]

log.cookie(file, level, overwrite, setLevel)
For reading and writing log level cookies for for the setting of the log level.
PARAMETER TYPE DESCRIPTION
file String or File Object The file path of the log cookie.
The same rules apply for the file cookie file name as in the log.setFile() method, as such the file name and path might not be the expected one. The actual cookie file path can be extracted from the object returned by the method. [Optional – default: A cookie file will be created in the temporary folder and called COOKIE_Script Name_Year_Month_Date.txt for example COOKIE_Script2_2017_Feb_21.txt effectively leaving out the file name creates a temporary cookie that will be valid until midnight]
level String or Integer The level from which the logs should be logged. [Optional – default: NONE] The level object accepts any of the values listed by the setLevel() method.
overwrite Boolean If the cookie should be overwritten if it already exists [Optional – default: false]
setLevel Boolean If the log level should be set to the cookies level value [Optional – default: true]
RETURNS Object {path: The actual path of the file cookie, level: the integer value of the level}
NOTES A typical usage of the log.cookie method would be in a distributed production script. Normally one wouldn't want the log to be automatically created, instead one would want a method for the user to activate the logging by either manually changing the contents of the log cookie or by using a provided UI option.
This method also accepts use an object in the form of var myCookie = log.cookie({file: 'myCookie.txt', level: 'error', overwrite: true, setLevel: true});

log.setStatus(status)
For setting default log status
PARAMETER TYPE DESCRIPTION
status String Sets the default log status.
Accepts the following non case sensitive strings and their abbreviations.
RE: 'RESULT', ST: 'STOPPER', TI: 'TIMER', T: 'TRACE'
D: 'DEBUG', L: 'LOG', CO: 'CONSTANT', F: 'FUNCTION', R: 'RETURN', V: 'VARIABLE', S: 'STACK'
I: 'INFO', IM: 'IMPORTANT'
W: 'WARNING'
B: 'BUG', C: 'CRITICAL', E: 'ERROR'
FA: 'FATAL'
Custom statuses can also be used.
RETURNS String The full unabbreviated status
NOTES The level associated with each status is listed by the log.setLevel() method
[1] [LOG] blah [Thu Mar 02 2017 07:44:26 GMT+0200 618ms] [2] [IMPORTANT] blah [Thu Mar 02 2017 07:44:26 GMT+0200 619ms] [3] [CUSTOM] blah [Thu Mar 02 2017 07:44:26 GMT+0200 619ms]

log.setFile(file)
For setting file were the log will be written to.
PARAMETER TYPE DESCRIPTION
file String of File Object Accepts either the File Object or a String of the full path to the log or just the file name of the log in which case it will be place in the systems temporary folder.
[Optional – default: If a path was previously set then that path will be used otherwise the log file will be created in the temporary folder and called LOG_Script Name_Year_Month_Date.log for example LOG_Script2_2017_Feb_21.log]
RETURNS File Object The File Object (which may or may not yet exist)
NOTES The log will only be written to (and created) if the log.write value is true (which is it's default value). If it's not the file will be ready to be created as soon as a log is entered after setting the log.write value value to true. The log entries also have to be of a status equal or higher than the log level (the default log level is 2).
The setFile method uses a systematic fail back file naming process in the event that the log file cannot be written to. If the given path can not be used (for example the files for some reason set to readonly) then a date integer will be added to the name. i.e. if the path '~/Documents/myLog.log' couldn't be written to then '~/Documents/myLog_1485181571090.log' will be tired. If that doesn't work then try the original name in the temp directory path/to/temp/directory/myLog.log. If that's no good then try a safe name in the temp folder path/to/temp/directory/LOG_1485181571090.log.
[1] [LOG] Hi again [Sun Mar 05 2017 10:05:02 GMT+0200 562ms]

log.get()
For retrieving individual or ranges of log entries.
PARAMETER TYPE DESCRIPTION
Integer or Array of 2 Integers The log line or log range to be returned.
If an Integer n is given then log entry n will be returned. If an array [start, end] is given then the range of log entries from start to end with be returned. Negative integers can be given -1 is the last entry -2 is the second last entry 1 is the first entry [Optional – default: [1, -1] i.e. the entire log store]
Integer or Array Same as above.
The more argument you use the more log lines or ranges will be returned
RETURNS String The strings of the selected log entries
NOTES The log entires can only be fetched if the logs are stored in the computers memory. By default the log.store value is set to false the logs are NOT stored in the computers memory. To store the logs in the computers memory either at the creation of the log factory set the store value to true var log = new LogFactory({store: true}); or directly set log.store = true.
When on earth would you want to do this? With small production scripts which are not overly logging and you generally don't need the logs, you can store the logs just in the memory by setting the log.write value to false and the log.store value to true. You can then access the log if needed in a try catch error report. Normally you might use something like alert('The last 20 log entries were\n' + log.get([-20, -1]));
[1000] [INFO] Silly fake error report.
[1] [LOG] Log entry [1] ([-999] from the end) [Thu Mar 02 2017 09:07:09 GMT+0200 737ms] [2] [LOG] Log entry [2] ([-998] from the end) [Thu Mar 02 2017 09:07:09 GMT+0200 737ms] [3] [LOG] Log entry [3] ([-997] from the end) [Thu Mar 02 2017 09:07:09 GMT+0200 737ms] [10] [LOG] Log entry [10] ([-990] from the end) [Thu Mar 02 2017 09:07:09 GMT+0200 737ms] [990] [LOG] Log entry [990] ([-10] from the end) [Thu Mar 02 2017 09:07:09 GMT+0200 784ms] [991] [LOG] Log entry [991] ([-9] from the end) [Thu Mar 02 2017 09:07:09 GMT+0200 784ms] [992] [LOG] Log entry [992] ([-8] from the end) [Thu Mar 02 2017 09:07:09 GMT+0200 784ms] [997] [LOG] Log entry [997] ([-3] from the end) [Thu Mar 02 2017 09:07:09 GMT+0200 784ms] [999] [LOG] Log entry [999] ([-1] from the end) [Thu Mar 02 2017 09:07:09 GMT+0200 784ms] [Thu Mar 02 2017 09:07:09 GMT+0200 785ms] [1001] [ERROR] 🐛ReferenceError: BUG is undefined at line: 13 [Thu Mar 02 2017 09:07:09 GMT+0200 786ms]

log.args(args, funct, line)
Logs information about a function and it's augments.
PARAMETER TYPE DESCRIPTION
args Function Augments The arguments of the function. Normally this would be the arguments of the function that calls the log.args() method, in which case one would use log.args(augments); the word augments should not be placed in quotes.
funct Function The function whose arguments are being parsed. Currently (2017) Adobe's extended script is based on ECMA version 3 (Published December 1999), the rest of the world is using version 7 (Published June 2016), hey not much changes in 4 versions and 16½+ of a highly developing language! As such the function can be retrieved from it's arguments using arguments.callee, from version 5 this is not allowed in strict mode. As such this argument is included as a prayer that Adobe will update their JavaScript version. [Optional – currently not needed]
line Integer You can include the line number that the method was called from by using log.args(augments, $.line). If the funct parameter is not passed then the second parameter will be the line parameter. [Optional – none]
RETURNS String The string of log entry produced
NOTES The log entry is allocated a "Function" status. If no value is provided for the functions named arguments then the value shown will be "NO VALUE PROVIDED". If a value is provided for the functions non-named arguments then the argument name shown will be arguments[n] where n is the index of the argument.
[1] [FUNCTION] -------------- Function Data: -------------- Function Name: anonymous Call stack: [(Script3)] F1(1,[Object:[object Object]]) Function Line around: 3 Arguments Provided: 2 Named Arguments: 3 Arguments Names: a, b, c ---------------- Argument Values: ---------------- a: 1 b: {a:3, b:{q:"sg", e:[23, 7, 234, 7, 4, "wt", [3, 6, 7, ({r:4})]]}} c: NO VALUE PROVIDED [Fri Feb 24 2017 12:17:08 GMT+0200 349ms]

log.values(values)
Logs the values of an object or array.
PARAMETER TYPE DESCRIPTION
values Object or Array The Object or Array whose values one wants mapped. This function is a useful way of capturing information on multiple variables. In a case where one wants to get a snapshot of the values a, b, c one can use log.values({a:a , b:b, c:c});
RETURNS String The string of log entry produced
[1] [VARIABLE] a: 3 b: {q:"sg", e:[23, 7, 234, 7, 4, "wt", [3, 6, 7, ({r:4})]]} [Wed Feb 22 2017 15:55:35 GMT+0200 738ms] [2] [VARIABLE] 0: 4 1: 5 2: 3 3: "sdf" 4: /dsfgsdg/ 5: 4 6: {w:425} foo: "bar" [Wed Feb 22 2017 15:55:35 GMT+0200 742ms]

log.stack()
Logs the call stack
RETURNS String The string of log entry produced
NOTES The log entry is allocated a "STACK" status. The stack order is as per the order of the $.stack property i.e. each listing is the caller of the listing below.
[1] [STACK] [(Script4)] F1(1,2) F2(3,0,undefined) [Wed Feb 22 2017 16:42:19 GMT+0200 829ms]

log.sumDiff(message)
Shows the difference between $.summary() calls.
PARAMETER TYPE DESCRIPTION
message String Message to be added to the log entry.
RETURNS String The string of log entry produced.
NOTES This method is for seeing how many wanted or unwanted variables you have created. Are you a tidy sort of guy or a dirty slob?
Thanks to Dirk Becker for permission to use his $.summary.difference() function, Cheers Dirk 🍺. The implementation here automatically calls garbage collection before execution.

Note: If you try the snippet on a persistent engine for example Illustrator then the results will differ from those shown here.

[1] [LOG] log.sumDiff() Demo [Fri Feb 24 2017 14:13:21 GMT+0200 707ms] [2] [INFO] Note that "Functions" will be added each 1st time a new log method is called [Fri Feb 24 2017 14:13:21 GMT+0200 707ms] [3] [VARIABLE] $.summary.difference(): 2 Array 1 RegExp 6 Function 1 (workspace) 1 Object [Fri Feb 24 2017 14:13:21 GMT+0200 708ms] [4] [VARIABLE] $.summary.difference(): 2 Array 2 RegExp 2 Object [Fri Feb 24 2017 14:13:21 GMT+0200 709ms] [5] [INFO] 😃Nothing new here [Fri Feb 24 2017 14:13:21 GMT+0200 709ms] [6] [VARIABLE] $.summary.difference(): Zilch - NONE - [Fri Feb 24 2017 14:13:21 GMT+0200 710ms]

log.file()
For access to the log file.
RETURNS File Object The log file object if one was defined. (undefined if not)
[1] [LOG] new File ("/private/var/folders/dp/kswbf4qd03d108xy4wdr_8240000gn/T/TemporaryItemsLOG_1488320198504.log") [Wed Mar 01 2017 00:16:38 GMT+0200 523ms]

log.execute() & log.show()
Opens the log file with the systems default application for opening the files with the suffix you have allocated to the log.
RETURNS Boolean If the file was opened.
NOTES With log save with a .log suffix the Mac will normally open the log with the Mac Console program. This in my opinion is pretty satisfactory. On Windows you will need to designate a program as the default program for opening .log files. I use Sublime Text. If you can call your log whatever your want (within reason), .txt, .html, .etc. and have a different default program open the log.

log.openFolder()
Opens the log folder containing the log file with Finder or Windows Explorer
RETURNS Boolean If the folder was opened.

log.close()
Closes the log file.
RETURNS Boolean If the file was closed.
NOTES This is for tidy people who don't like to leave files open

log.setCount(file)
Sets the log count for the next log entry.
PARAMETER TYPE DESCRIPTION
file Integer or File Object or String Accepts an integer to set the count to a specified number or the File Object of a log file or a String of the full path of the log file. [Optional – default: The current log file].
If the count is retrieved from a log file then the next log count will continue from the last entry of that file.
RETURNS Integer The log count for the next log entry.
NOTES This method is could be used if one is controlling multiple log files with a single log factory. The count property can be set directly using log.count = n; where n is an integer.

myLog1.log

[1] [LOG] Something in log 1 [Thu Feb 23 2017 15:00:22 GMT+0200 489ms] [2] [LOG] Something else in log 1 [Thu Feb 23 2017 15:00:22 GMT+0200 490ms] [3] [LOG] Yet another thing in log 1 [Thu Feb 23 2017 15:00:22 GMT+0200 495ms]

myLog2.log

[1] [LOG] Something in log 2 [Thu Feb 23 2017 15:00:22 GMT+0200 492ms] [-10] [LOG] Bored? [Thu Feb 23 2017 15:00:22 GMT+0200 497ms]

log.reset(all)
Resets the log factory to more or less it's default settings
PARAMETER TYPE DESCRIPTION
all Boolean If just the log store (i.e. the logs stored in the computers memory in the event that the factory was set up to remember them) and count should be reset or all the setting should be reset (like a factory reset on a phone). [Optional – default: true]

Timing Methods
These timing methods are to give a rough time of the execution of parts of the script.
For a more accurate method of timing function times I've posted my thoughts and a snippet on the Adobe InDesign scripting forum.

log.stopper(message)
For timing between 2 points.
message String The message that should be displayed before the log timing information [Optional – default: none].
RETURNS String The log produced.
NOTES This method is records the time lapsed between one stopper call and the next, automatically including the log counts of the points. I differs from the log.start() and log.stop() timing methods which interact with each other as pairs in the way that brackets do see the snippet by those methods.
[1] [STOPPER] Stopper start point From Log Factory Start to BEFORE LOG#1 took 3ms Starting Thu Feb 23 2017 17:16:51 GMT+0200 538ms Ending Thu Feb 23 2017 17:16:51 GMT+0200 541ms [Thu Feb 23 2017 17:16:51 GMT+0200 541ms] [2] [STOPPER] 1st loop From BEFORE LOG#1 to LOG#2 took 5ms Starting Thu Feb 23 2017 17:16:51 GMT+0200 541ms Ending Thu Feb 23 2017 17:16:51 GMT+0200 546ms [Thu Feb 23 2017 17:16:51 GMT+0200 546ms] [3] [STOPPER] 2nd loop From LOG#2 to LOG#3 took 3ms Starting Thu Feb 23 2017 17:16:51 GMT+0200 546ms Ending Thu Feb 23 2017 17:16:51 GMT+0200 549ms [Thu Feb 23 2017 17:16:51 GMT+0200 549ms]

log.start(message)
Registers a start point that will be matched by a pairing log.stop() call for timing purposes.
message String The message that goes before the start timing information. [Optional – default: none].
NOTES This method is used to provide a starting point from which the log.end() method times. See that method for when these methods would be used.
The logs produced by this method are assigned a "TIMER" level 1 status as such by default they will NOT be recorded. To enable this method set the log level to 1 or 0

log.stop(message)
Logs timing information from a matching start point created using log.start().
message String The message that goes before the stop timing information. [Optional – default: none].
RETURNS String The log produced.
NOTES This method with it's matching log.start() method is useful for when both an outer and inner timing is required, for example, the time it takes for the execution of an entire script (of set of scripts) and sections of that script and of individual functions within those sections of the script.
Each log.stop() method must have a matching log.start() method to which it is paired in the manner that brackets are, i.e. inner to inner, outer to outer.
The logs produced by this method are assigned a "TIMER" level 1 status as such by default they will NOT be recorded. To enable this method set the log level to 1 or 0
[1] [TIMER] After the longer loop @@@ STARTED [Thu Feb 23 2017 18:25:11 GMT+0200 540ms] After the shorter loop @@@ FINISHED [Thu Feb 23 2017 18:25:11 GMT+0200 540ms] TOTAL TIME [<1ms] [Thu Feb 23 2017 18:25:11 GMT+0200 540ms] [2] [TIMER] Before the longer loop **** STARTED [Thu Feb 23 2017 18:25:11 GMT+0200 493ms] After the shorter and longer loop **** FINISHED [Thu Feb 23 2017 18:25:11 GMT+0200 542ms] TOTAL TIME [49ms] [Thu Feb 23 2017 18:25:11 GMT+0200 542ms] [3] [TIMER] STARTED [Thu Feb 23 2017 18:25:11 GMT+0200 493ms] After Zzz FINISHED [Thu Feb 23 2017 18:25:12 GMT+0200 47ms] TOTAL TIME [554ms] [Thu Feb 23 2017 18:25:12 GMT+0200 47ms] [4] [TIMER] STARTED [Thu Feb 23 2017 18:25:12 GMT+0200 48ms] FINISHED [Thu Feb 23 2017 18:25:12 GMT+0200 48ms] TOTAL TIME [<1ms] [Thu Feb 23 2017 18:25:12 GMT+0200 48ms]


The LogFactory script 💾

LogFactory.jsx CopyRawDownload

Leave a Reply

Your email address will not be published. Required fields are marked *