Repository: pinojs/pino
Pull request #469 (2018-08-05 11:10:57)

Update from master
This is a pull from master.

Let me know.


Patch:
diff --git a/docs/transports.md b/docs/transports.md
index cd0bf3d..599a4b5 100644
--- a/docs/transports.md
+++ b/docs/transports.md
@@ -71,11 +71,11 @@ PR's to this document are welcome for any new transports!
 + [pino-couch](#pino-couch)
 + [pino-elasticsearch](#pino-elasticsearch)
 + [pino-mq](#pino-mq)
++ [pino-papertrail](#pino-papertrail)
 + [pino-redis](#pino-redis)
 + [pino-socket](#pino-socket)
 + [pino-syslog](#pino-syslog)
 
-
 <a id="pino-couch"></a>
 ### pino-couch
 
@@ -154,6 +154,20 @@ pino-mq -g
 
 For full documentation of command line switches and configuration see [the `pino-mq` readme](https://github.com/itavy/pino-mq#readme)
 
+<a id="pino-papertrail"></a>
+### pino-papertrail
+pino-papertrail is a transport that will forward logs to the [papertrail](https://papertrailapp.com) log service through an UDPv4 socket.
+
+Given an application `foo` that logs via pino, and a papertrail destination that collects logs on port UDP `12345` on address `bar.papertrailapp.com`, you would use `pino-papertrail`
+like so:
+
+```
+node yourapp.js | pino-papertrail --host bar.papertrailapp.com --port 12345 --appname foo
+```
+
+
+for full documentation of command line switches read [readme](https://github.com/ovhemert/pino-papertrail#readme)
+
 <a id="pino-redis"></a>
 ### pino-redis
 
diff --git a/lib/tools.js b/lib/tools.js
index 809fc36..480201a 100644
--- a/lib/tools.js
+++ b/lib/tools.js
@@ -86,7 +86,10 @@ function asJson (obj, msg, num, time) {
   if (hasObj === true) {
     var notHasOwnProperty = obj.hasOwnProperty === undefined
     if (objError === true) {
-      data += ',"type":"Error","stack":' + stringify(obj.stack)
+      data += ',"type":"Error"'
+      if (obj.stack !== undefined) {
+        data += ',"stack":' + stringify(obj.stack)
+      }
     }
     // if global serializer is set, call it first
     if (serializers[wildcardGsym]) {


Test patch:
diff --git a/test/basic.test.js b/test/basic.test.js
index 345cdd5..a1e43ab 100644
--- a/test/basic.test.js
+++ b/test/basic.test.js
@@ -455,3 +455,29 @@ test('when safe is true it should ONLY use `fast-safe-stringify`', async ({deepE
   const { a } = await once(stream, 'data')
   deepEqual(a, { a: '[Circular]' })
 })
+
+test('when safe is true, fast-safe-stringify must be used when interpolating', async (t) => {
+  const stream = sink()
+  const instance = pino({safe: true}, stream)
+
+  const o = { a: { b: {} } }
+  o.a.b.c = o.a.b
+  instance.info('test', o)
+
+  const { msg } = await once(stream, 'data')
+  t.is(msg, 'test {"a":{"b":{"c":"[Circular]"}}}')
+})
+
+test('when safe is false, interpolation should throw', async (t) => {
+  const stream = sink()
+  const instance = pino({safe: false}, stream)
+  var o = { a: { b: {} } }
+  o.a.b.c = o.a.b
+  try {
+    instance.info('test', o)
+  } catch (e) {
+    t.is(e.message, 'Converting circular structure to JSON')
+    return
+  }
+  t.fail('must throw')
+})
diff --git a/test/error.test.js b/test/error.test.js
index 749b6e6..4d33bc8 100644
--- a/test/error.test.js
+++ b/test/error.test.js
@@ -122,3 +122,34 @@ test('an error with statusCode property is not confused for a http response', as
     v: 1
   })
 })
+
+test('stack is omitted if it is not set on err', t => {
+  t.plan(2)
+  var err = new Error('myerror')
+  delete err.stack
+  var instance = pino(sink(function (chunk, enc, cb) {
+    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
+    delete chunk.time
+    t.equal(chunk.hasOwnProperty('stack'), false)
+    cb()
+  }))
+
+  instance.level = name
+  instance[name](err)
+})
+
+test('stack is rendered as any other property if it\'s not a string', t => {
+  t.plan(3)
+  var err = new Error('myerror')
+  err.stack = null
+  var instance = pino(sink(function (chunk, enc, cb) {
+    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
+    delete chunk.time
+    t.equal(chunk.hasOwnProperty('stack'), true)
+    t.equal(chunk.stack, null)
+    cb()
+  }))
+
+  instance.level = name
+  instance[name](err)
+})