Skip to content

Commit

Permalink
feat: Add support for css outputs
Browse files Browse the repository at this point in the history
  • Loading branch information
sospedra committed Dec 29, 2015
1 parent 8e4e8ee commit d454b72
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 40 deletions.
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,28 @@
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)


#### Logatim is an isomorphic logger which implements log levels and ANSI styles.


Finally you can use the same logger for the **server and client side** of your applications. Log for developers using **colors, underlines, etc.** in order to transform the terminal in an authenitc debugger machine. And log for production **managing exactly what have** and what have not **to be outputed**.

## Why?
I've been codgin for a long time and I've always feel that we need a better approach to the logging issue. I've researched a lot about the available logger modules and I've even run a [questionary](https://docs.google.com/forms/d/10cZEXVc7aA29JBjoJFsTnTd8tf-RxrwlgusZrg9HW90) about this topic. After this inquiry I think that **the most suitable logger should combines these six elemental features**:

## Quick start
- [ ] 1. **Free outputs**: it should be able to stream the logs anywhere and to multiples targets at the same time.
- [x] 2. **Levels**: it should handle which levels should be printing or not.
- [x] 3. **Styles**: as a very useful resource while developing, it should implements colors, bolds, etc.
- [x] 4. **Cross-platform**: it should run in all the browsers and all the node versions. This includes the different Javascript specifications.
- [x] 5. **Human-like**: it shouldn't have been any learning curve, nor complex configurations; just require and go.
- [ ] 6. **Customizable**: it should accept addons and plugins in order to keep a light and powerful core which can be extended for specific situations.

## Installation

Choose one of the following options:

1. Install it **via npm**: `npm install logatim --save`
2. Download from the `dist` folder the **stand-alone specification** which fits better for you: `var`, `commonjs`, `umd` or `amd`.
2. Download from the `dist` folder the **stand-alone specification** which fits better for you: `var`, `commonjs`, `umd` or `amd`. *Note that the installation via `npm` uses the umd pattern so should work in all the environments.*


## Features
Expand Down Expand Up @@ -113,6 +124,18 @@ npm run build
# send the PR, yaaay!
```

### Todo list

If you feel that the force is strong in Logatim keep an eye to the todo list and maybe you find something you're willing to make ;)

* Add the possibility to stream the output elsewhere than the console.
* Add the CI for client-side environments.
* Add Logatim to other source providers: bower, a CDN, etc.
* Write the technical in-code documentation.

## Dat name, tho
Logatim comes from a combination of the words **[log](https://en.wikipedia.org/wiki/Logfile)** and **[verbatim](https://en.wiktionary.org/wiki/verbatim)**. The first one is obviously referred to the cutten trunk... lol no, it's for the coding logfiles. And the second one is a Latin term that can be translated as *word for word*. So, the term Logatim could be loosely translated as **log for log**.

## License
The code is available under the [ISC license](LICENSE.txt).

Expand Down
2 changes: 1 addition & 1 deletion dist/logatim.var.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

104 changes: 103 additions & 1 deletion lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,107 @@ module.exports = {
WARN: 3,
ERROR: 4,
SILENT: 5
}
},
STYLES: {
bold: {
ansi: { open: '\u001b[1m', close: '\u001b[22m' },
css: { open: '\u001b[1m', close: '\u001b[22m' }
},
dim: {
ansi: { open: '\u001b[2m', close: '\u001b[22m' },
css: { open: '\u001b[2m', close: '\u001b[22m' }
},
italic: {
ansi: { open: '\u001b[3m', close: '\u001b[23m' },
css: { open: '\u001b[3m', close: '\u001b[23m' }
},
underline: {
ansi: { open: '\u001b[4m', close: '\u001b[24m' },
css: { open: '\u001b[4m', close: '\u001b[24m' }
},
inverse: {
ansi: { open: '\u001b[7m', close: '\u001b[27m' },
css: { open: '\u001b[7m', close: '\u001b[27m' }
},
hidden: {
ansi: { open: '\u001b[8m', close: '\u001b[28m' },
css: { open: '\u001b[8m', close: '\u001b[28m' }
},
strikethrough: {
ansi: { open: '\u001b[9m', close: '\u001b[29m' },
css: { open: '\u001b[9m', close: '\u001b[29m' }
},
black: {
ansi: { open: '\u001b[30m', close: '\u001b[39m' },
css: { open: '\u001b[30m', close: '\u001b[39m' }
},
red: {
ansi: { open: '\u001b[31m', close: '\u001b[39m' },
css: { open: '\u001b[31m', close: '\u001b[39m' }
},
green: {
ansi: { open: '\u001b[32m', close: '\u001b[39m' },
css: { open: '\u001b[32m', close: '\u001b[39m' }
},
yellow: {
ansi: { open: '\u001b[33m', close: '\u001b[39m' },
css: { open: '\u001b[33m', close: '\u001b[39m' }
},
blue: {
ansi: { open: '\u001b[34m', close: '\u001b[39m' },
css: { open: '\u001b[34m', close: '\u001b[39m' }
},
magenta: {
ansi: { open: '\u001b[35m', close: '\u001b[39m' },
css: { open: '\u001b[35m', close: '\u001b[39m' }
},
cyan: {
ansi: { open: '\u001b[36m', close: '\u001b[39m' },
css: { open: '\u001b[36m', close: '\u001b[39m' }
},
white: {
ansi: { open: '\u001b[37m', close: '\u001b[39m' },
css: { open: '\u001b[37m', close: '\u001b[39m' }
},
gray: {
ansi: { open: '\u001b[90m', close: '\u001b[39m' },
css: { open: '\u001b[90m', close: '\u001b[39m' }
},
grey: {
ansi: { open: '\u001b[90m', close: '\u001b[39m' },
css: { open: '\u001b[90m', close: '\u001b[39m' }
},
bgBlack: {
ansi: { open: '\u001b[40m', close: '\u001b[49m' },
css: { open: '\u001b[40m', close: '\u001b[49m' }
},
bgRed: {
ansi: { open: '\u001b[41m', close: '\u001b[49m' },
css: { open: '\u001b[41m', close: '\u001b[49m' }
},
bgGreen: {
ansi: { open: '\u001b[42m', close: '\u001b[49m' },
css: { open: '\u001b[42m', close: '\u001b[49m' }
},
bgYellow: {
ansi: { open: '\u001b[43m', close: '\u001b[49m' },
css: { open: '\u001b[43m', close: '\u001b[49m' }
},
bgBlue: {
ansi: { open: '\u001b[44m', close: '\u001b[49m' },
css: { open: '\u001b[44m', close: '\u001b[49m' }
},
bgMagenta: {
ansi: { open: '\u001b[45m', close: '\u001b[49m' },
css: { open: '\u001b[45m', close: '\u001b[49m' }
},
bgCyan: {
ansi: { open: '\u001b[46m', close: '\u001b[49m' },
css: { open: '\u001b[46m', close: '\u001b[49m' }
},
bgWhite: {
ansi: { open: '\u001b[47m', close: '\u001b[49m' },
css: { open: '\u001b[47m', close: '\u001b[49m' }
}
}
}
55 changes: 28 additions & 27 deletions lib/levels.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,31 @@ const levels = module.exports = {}

levels.getLevel = level => Object.keys(constants.LEVELS)[level]

levels.setLevel = level => {
levels.setLevel = (level, isNode) => {
if (typeof level === 'string' && constants.LEVELS[level.toUpperCase()] !== undefined) {
level = constants.LEVELS[level.toUpperCase()]
}

if (typeof level === 'number' && level >= 0 && level <= constants.LEVELS.SILENT) {
levels.persistLevel(level)
levels.persistLevel(level, isNode)

return level
} else {
throw new Error(`logatim.setLevel() called with invalid level: ${level}`)
}
}

levels.persistLevel = (levelNum) => {
levels.persistLevel = (levelNum, isNode) => {
let levelName = (constants.LOG_METHODS[levelNum] || 'silent').toUpperCase()
let sk = constants.STORAGE_KEY

// server side
GLOBAL[sk] = levelName
if (isNode) return GLOBAL[sk] = levelName

// front side
// else front side
// Use localStorage if available
try {
window.localStorage[sk] = levelName
return
return window.localStorage[sk] = levelName
} catch (ignore) {}

// Use session cookie as fallback
Expand All @@ -40,33 +39,35 @@ levels.persistLevel = (levelNum) => {
} catch (ignore) {}
}

levels.getPersistedLevel = () => {
levels.getPersistedLevel = (isNode) => {
let storedLevel
let sk = constants.STORAGE_KEY

// front side
// try to get it from localStorage
try {
storedLevel = window.localStorage[sk]
} catch (ignore) {}

// if fails look for it on the cookies document
if (typeof storedLevel === 'undefined') {
// server side
if (isNode) {
storedLevel = GLOBAL[sk]
} else {
// front side
// try to get it from localStorage
try {
let cookie = window.document.cookie
let location = cookie.indexOf(encodeURIComponent(sk) + '=')

if (location) storedLevel = /^([^;]+)/.exec(cookie.slice(location))[1]
storedLevel = window.localStorage[sk]
} catch (ignore) {}
}

// if everything fails return undefined, like nothing happened
if (constants.LEVELS[storedLevel] === undefined) {
storedLevel = undefined
}
// if fails look for it on the cookies document
if (typeof storedLevel === 'undefined') {
try {
let cookie = window.document.cookie
let location = cookie.indexOf(encodeURIComponent(sk) + '=')

// server side
storedLevel = GLOBAL[sk]
if (location) storedLevel = /^([^;]+)/.exec(cookie.slice(location))[1]
} catch (ignore) {}
}

// if everything fails return undefined, like nothing happened
if (constants.LEVELS[storedLevel] === undefined) {
storedLevel = undefined
}
}

return storedLevel
}
18 changes: 12 additions & 6 deletions lib/logatim.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
'use strict'

const ansi = require('ansi-styles')
const constants = require('./constants')
const levels = require('./levels')
const logs = require('./logs')
const isNode = (typeof process === 'object' && process.toString() === '[object process]')

let currentLevel = 3

Expand All @@ -13,19 +14,24 @@ const logatim = module.exports = message => {
speaker.getLevel = () => levels.getLevel(currentLevel)

speaker.setLevel = (level) => {
currentLevel = levels.setLevel(level)
currentLevel = levels.setLevel(level, isNode)
logs.updateLogMethods(speaker, message, currentLevel)
}

// Colors
Object.keys(ansi).forEach(style => {
Object.defineProperty(speaker, style, {
get: () => logatim(`${message}${ansi[style].open}`)
Object.keys(constants.STYLES).forEach(styleName => {
// use ansi or css codes depending on the current environment
let style = isNode
? constants.STYLES[styleName].ansi
: constants.STYLES[styleName].css

Object.defineProperty(speaker, styleName, {
get: () => logatim(`${message}${style.open}`)
})
})

// Refresh reachable methods
speaker.setLevel(levels.getPersistedLevel() || currentLevel)
speaker.setLevel(levels.getPersistedLevel(isNode) || currentLevel)
logs.updateLogMethods(speaker, message, currentLevel)

return speaker
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
},
"author": "Rubén Sospedra <[email protected]> (http://sospedra.me)",
"license": "ISC",
"dependencies": {
"ansi-styles": "^2.1.0"
},
"dependencies": {},
"devDependencies": {
"babel-core": "^6.3.26",
"babel-loader": "^6.2.0",
Expand Down

0 comments on commit d454b72

Please sign in to comment.