├── .gitignore
├── tsconfig.json
├── gulpfile.js
├── typings.json
├── package.json
├── lib
├── winston-dynamodb.d.ts
└── winston-dynamodb.js
├── README.md
├── winston-dynamodb.coffee
├── winston-dynamodb.js
└── src
└── winston-dynamodb.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | *.db
2 | .DS_Store
3 | .project
4 | node_modules
5 | .metadata
6 | *.tmproj
7 | *.sublime-project
8 | dump.rdb
9 | .idea
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "module": "commonjs",
5 | "target": "es5",
6 | "noImplicitAny": false,
7 | "outDir": "lib",
8 | "sourceMap": false
9 | },
10 | "exclude": [
11 | "lib",
12 | "node_modules"
13 | ]
14 | }
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require("gulp"),
2 | gutil = require("gulp-util"),
3 | coffee = require("gulp-coffee");
4 |
5 | gulp.task("coffee", function() {
6 | gulp.src("./**/*.coffee")
7 | .pipe(coffee({bare: false}).on("error", gutil.log))
8 | .pipe(gulp.dest("./"));
9 | });
10 |
11 | gulp.task("default", ["coffee"]);
--------------------------------------------------------------------------------
/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "globalDependencies": {
3 | "aws-sdk": "registry:dt/aws-sdk#0.0.0+20160802165139",
4 | "lodash": "registry:dt/lodash#4.14.0+20160802150749",
5 | "node": "registry:env/node#6.0.0+20160723033700",
6 | "winston": "registry:dt/winston#0.0.0+20160417152829"
7 | },
8 | "dependencies": {
9 | "node-uuid": "registry:npm/node-uuid#1.4.7+20160723033700"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "winston-dynamodb",
3 | "description": "A Winston transport for Amazon DynamoDB",
4 | "version": "0.3.1",
5 | "author": {
6 | "name": "JeongWoo Chang",
7 | "email": "inspired.jw@gmail.com"
8 | },
9 | "homepage": "https://github.com/inspiredjw/winston-dynamodb",
10 | "repository": {
11 | "type": "git",
12 | "url": "git://github.com/inspiredjw/winston-dynamodb.git"
13 | },
14 | "typings": "./lib/winston-dynamodb.d.ts",
15 | "keywords": [
16 | "logging",
17 | "sysadmin",
18 | "tools",
19 | "winston",
20 | "amazon",
21 | "dynamodb",
22 | "aws"
23 | ],
24 | "dependencies": {
25 | "aws-sdk": "^2.1.32",
26 | "lodash": "^4.12.0",
27 | "node-uuid": "1.4.*"
28 | },
29 | "devDependencies": {
30 | "gulp": "^3.9.0",
31 | "gulp-coffee": "^2.3.1",
32 | "gulp-util": "^3.0.5",
33 | "winston": "^1.0.0"
34 | },
35 | "main": "./winston-dynamodb"
36 | }
37 |
--------------------------------------------------------------------------------
/lib/winston-dynamodb.d.ts:
--------------------------------------------------------------------------------
1 | import * as winston from 'winston';
2 | import { TransportInstance } from 'winston';
3 | export interface DynamoDBTransportOptions {
4 | useEnvironment?: boolean;
5 | accessKeyId?: string;
6 | secretAccessKey?: string;
7 | region?: string;
8 | tableName: string;
9 | level: string;
10 | dynamoDoc?: boolean;
11 | }
12 | export interface DynamoDBTransportInstance extends TransportInstance {
13 | new (options?: DynamoDBTransportOptions): DynamoDBTransportInstance;
14 | }
15 | export declare class DynamoDB extends winston.Transport implements DynamoDBTransportInstance {
16 | regions: string[];
17 | name: string;
18 | level: string;
19 | db: any;
20 | AWS: any;
21 | region: string;
22 | tableName: string;
23 | dynamoDoc: boolean;
24 | constructor(options?: DynamoDBTransportOptions);
25 | log(level: any, msg: any, meta: any, callback: any): any;
26 | }
27 | declare module "winston" {
28 | interface Transports {
29 | DynamoDB: DynamoDB;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DynamoDB Transport for Winston
2 |
3 | A DynamoDB transport for [winston][0].
4 |
5 | ## Usage
6 | ```javascript
7 | var winston = require('winston');
8 |
9 | require('winston-dynamodb').DynamoDB;
10 |
11 | winston.add(winston.transports.DynamoDB, options);
12 | ```
13 |
14 | ## Options
15 |
16 | ```
17 | accessKeyId : your AWS access key id
18 | secretAccessKey : your AWS secret access key
19 | region : the region where the domain is hosted
20 | useEnvironment : use process.env values for AWS access, secret, & region
21 | tableName : DynamoDB table name
22 | dynamoDoc : if this is set to true, the *meta* parameter will be stored as a subobject using DynamoDB's DocumentClient rather than as a JSON string.
23 | ```
24 |
25 | ## Prerequisite
26 |
27 | Make a table with `tableName`
28 |
29 | The table schema depends on how you intend to use it.
30 |
31 | #### Simplest
32 |
33 | The table should have
34 |
35 | - hash key: (String) level
36 | - range key: (String) timestamp
37 |
38 | > Note: Timestamp has a millisecond resolution. So whether this key setup will work depends on how many log messages you expect.
39 | >
40 | > That is, the uniqueness of level + timestamp means max: 1 log message of a given level per millisecond.
41 |
42 | It is nice to have it as a range key for queries.
43 |
44 | #### More Robust
45 |
46 | To ensure you can log as many messages as you like, alternatively use:
47 |
48 | - hash key: (String) id (Will be a uuid)
49 | - range key: (String) timestamp
50 |
51 | Using the id as hash ensures that all log items will have unique keys and be included.
52 |
53 | ## Region
54 |
55 | Available Regions
56 |
57 | - us-east-1
58 | - us-west-1
59 | - us-west-2
60 | - eu-west-1
61 | - ap-northeast-1
62 | - ap-southeast-1
63 | - ap-southeast-2
64 | - sa-east-1
65 |
66 | ## AWS Credentials
67 |
68 | All of these options are values that you can find from your Amazon Web Services account: 'accessKeyId', 'secretAccessKey' and 'awsAccountId'.
69 |
70 | Alternatively, pass in useEnvironment: true and the process.env values will be used.
71 | > (Functions in AWS Lambda environment and works with default AWS Credentials Global Configuration .config in other node environments.)
72 |
73 | ## Installation
74 |
75 | ``` bash
76 | $ npm install winston
77 | $ npm install winston-dynamodb
78 | ```
79 |
80 | #### Author: [JeongWoo Chang](http://twitter.com/inspiredjw)
81 |
82 | [0]: https://github.com/winstonjs/winston
--------------------------------------------------------------------------------
/winston-dynamodb.coffee:
--------------------------------------------------------------------------------
1 | winston = require "winston"
2 | util = require "util"
3 | AWS = require "aws-sdk"
4 | uuid = require("node-uuid")
5 | _ = require "lodash"
6 | hostname = require("os").hostname()
7 |
8 | # Return timestamp with YYYY-MM-DD HH:mm:ss
9 | datify = (timestamp) ->
10 | date = new Date timestamp
11 | date =
12 | year: date.getFullYear()
13 | month: date.getMonth() + 1
14 | day: date.getDate()
15 |
16 | hour: date.getHours()
17 | minute: date.getMinutes()
18 | second: date.getSeconds()
19 | millisecond: date.getMilliseconds()
20 |
21 | keys = _.without Object.keys date, "year", "month", "day"
22 | date[key] = "0" + date[key] for key in keys when date[key] < 10
23 | "#{date.year}-#{date.month}-#{date.day} #{date.hour}:#{date.minute}:#{date.second}.#{date.millisecond}"
24 |
25 | DynamoDB = exports.DynamoDB = (options = {}) ->
26 | regions = [
27 | "us-east-1"
28 | "us-west-1"
29 | "us-west-2"
30 | "eu-west-1"
31 | "eu-central-1"
32 | "ap-northeast-1"
33 | "ap-northeast-2"
34 | "ap-southeast-1"
35 | "ap-southeast-2"
36 | "sa-east-1"
37 | ]
38 |
39 | if options.useEnvironment
40 | options.accessKeyId = process.env.AWS_ACCESS_KEY_ID
41 | options.secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY
42 | options.region = process.env.AWS_REGION
43 |
44 | unless options.accessKeyId?
45 | throw new Error "need accessKeyId"
46 |
47 | unless options.secretAccessKey?
48 | throw new Error "need secretAccessKey"
49 |
50 | unless options.region?
51 | throw new Error "need region"
52 |
53 | unless options.region in regions
54 | throw new Error "unavailable region given"
55 |
56 | unless options.tableName?
57 | throw new Error "need tableName"
58 |
59 | unless options.useEnvironment
60 | AWS.config.update
61 | accessKeyId: options.accessKeyId
62 | secretAccessKey: options.secretAccessKey
63 | region: options.region
64 |
65 | # Winston Options
66 | @.name = "dynamodb"
67 | @.level = options.level or "info"
68 |
69 | # DynamoDB Options=
70 | @.db = new AWS.DynamoDB()
71 | @.AWS = AWS
72 | @.region = options.region
73 |
74 | # a-z, A-Z, 0-9, _ (underscore), - (hyphen) and . (period)
75 | @.tableName = options.tableName
76 | @.dynamoDoc = options.dynamoDoc
77 |
78 | util.inherits DynamoDB, winston.Transport
79 |
80 | DynamoDB::log = (level, msg, meta, callback) ->
81 | putCallback = (err, data) =>
82 | if err
83 | @.emit "error", err
84 | callback err, null if callback
85 | else
86 | @.emit "logged"
87 | callback null, "logged" if callback
88 |
89 | if @.dynamoDoc == true
90 | params =
91 | TableName: @.tableName
92 | Item:
93 | id: uuid.v4()
94 | level: level
95 | timestamp: datify Date.now()
96 | msg: msg
97 | hostname: hostname
98 |
99 | unless _.isEmpty meta
100 | params.Item.meta = meta
101 |
102 | dynamoDocClient = new @.AWS.DynamoDB.DocumentClient({
103 | service: @.db
104 | })
105 | dynamoDocClient.put params, putCallback
106 | else
107 | params =
108 | TableName: @.tableName
109 | Item:
110 | id:
111 | "S": uuid.v4()
112 | level:
113 | "S": level
114 | timestamp:
115 | "S": datify Date.now()
116 | msg:
117 | "S": msg
118 | hostname:
119 | "S": hostname
120 |
121 | unless _.isEmpty meta
122 | params.Item.meta = "S": JSON.stringify meta
123 |
124 | @.db.putItem params, putCallback
125 |
126 | # Add DynamoDB to the transports by winston
127 | winston.transports.DynamoDB = DynamoDB
128 |
--------------------------------------------------------------------------------
/winston-dynamodb.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var AWS, DynamoDB, _, datify, hostname, util, uuid, winston,
3 | indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
4 |
5 | winston = require("winston");
6 |
7 | util = require("util");
8 |
9 | AWS = require("aws-sdk");
10 |
11 | uuid = require("node-uuid");
12 |
13 | _ = require("lodash");
14 |
15 | hostname = require("os").hostname();
16 |
17 | datify = function(timestamp) {
18 | var date, i, key, keys, len;
19 | date = new Date(timestamp);
20 | date = {
21 | year: date.getFullYear(),
22 | month: date.getMonth() + 1,
23 | day: date.getDate(),
24 | hour: date.getHours(),
25 | minute: date.getMinutes(),
26 | second: date.getSeconds(),
27 | millisecond: date.getMilliseconds()
28 | };
29 | keys = _.without(Object.keys(date, "year", "month", "day"));
30 | for (i = 0, len = keys.length; i < len; i++) {
31 | key = keys[i];
32 | if (date[key] < 10) {
33 | date[key] = "0" + date[key];
34 | }
35 | }
36 | return date.year + "-" + date.month + "-" + date.day + " " + date.hour + ":" + date.minute + ":" + date.second + "." + date.millisecond;
37 | };
38 |
39 | DynamoDB = exports.DynamoDB = function(options) {
40 | var ref, regions;
41 | if (options == null) {
42 | options = {};
43 | }
44 | regions = ["localhost", "us-east-1", "us-west-1", "us-west-2", "eu-west-1", "eu-central-1", "ap-northeast-1", "ap-northeast-2", "ap-southeast-1", "ap-southeast-2", "sa-east-1"];
45 | if (options.useEnvironment) {
46 | options.accessKeyId = process.env.AWS_ACCESS_KEY_ID;
47 | options.secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
48 | options.region = process.env.AWS_REGION;
49 | }
50 | if (options.accessKeyId == null) {
51 | throw new Error("need accessKeyId");
52 | }
53 | if (options.secretAccessKey == null) {
54 | throw new Error("need secretAccessKey");
55 | }
56 | if (options.region == null) {
57 | throw new Error("need region");
58 | }
59 | if (ref = options.region, indexOf.call(regions, ref) < 0) {
60 | throw new Error("unavailable region given");
61 | }
62 | if (options.tableName == null) {
63 | throw new Error("need tableName");
64 | }
65 | if (!options.useEnvironment) {
66 | AWS.config.update({
67 | accessKeyId: options.accessKeyId,
68 | secretAccessKey: options.secretAccessKey,
69 | region: options.region
70 | });
71 | }
72 | this.name = "dynamodb";
73 | this.level = options.level || "info";
74 | if (options.region == "localhost") {
75 | this.db = new AWS.DynamoDB({
76 | endpoint: new AWS.Endpoint(options.endpoint)
77 | });
78 | }
79 | else {
80 | this.db = new AWS.DynamoDB();
81 | }
82 | this.AWS = AWS;
83 | this.region = options.region;
84 | this.tableName = options.tableName;
85 | return this.dynamoDoc = options.dynamoDoc;
86 | };
87 |
88 | util.inherits(DynamoDB, winston.Transport);
89 |
90 | DynamoDB.prototype.log = function(level, msg, meta, callback) {
91 | var dynamoDocClient, params, putCallback;
92 | putCallback = (function(_this) {
93 | return function(err, data) {
94 | if (err) {
95 | _this.emit("error", err);
96 | if (callback) {
97 | return callback(err, null);
98 | }
99 | } else {
100 | _this.emit("logged");
101 | if (callback) {
102 | return callback(null, "logged");
103 | }
104 | }
105 | };
106 | })(this);
107 | if (this.dynamoDoc === true) {
108 | params = {
109 | TableName: this.tableName,
110 | Item: {
111 | id: uuid.v4(),
112 | level: level,
113 | timestamp: datify(Date.now()),
114 | msg: msg,
115 | hostname: hostname
116 | }
117 | };
118 | if (!_.isEmpty(meta)) {
119 | params.Item.meta = meta;
120 | }
121 | dynamoDocClient = new this.AWS.DynamoDB.DocumentClient({
122 | service: this.db
123 | });
124 | return dynamoDocClient.put(params, putCallback);
125 | } else {
126 | params = {
127 | TableName: this.tableName,
128 | Item: {
129 | id: {
130 | "S": uuid.v4()
131 | },
132 | level: {
133 | "S": level
134 | },
135 | timestamp: {
136 | "S": datify(Date.now())
137 | },
138 | msg: {
139 | "S": msg
140 | },
141 | hostname: {
142 | "S": hostname
143 | }
144 | }
145 | };
146 | if (!_.isEmpty(meta)) {
147 | params.Item.meta = {
148 | "S": JSON.stringify(meta)
149 | };
150 | }
151 | return this.db.putItem(params, putCallback);
152 | }
153 | };
154 |
155 | winston.transports.DynamoDB = DynamoDB;
156 |
157 | }).call(this);
158 |
--------------------------------------------------------------------------------
/src/winston-dynamodb.ts:
--------------------------------------------------------------------------------
1 | import * as winston from 'winston';
2 | import * as util from 'util';
3 | import * as AWS from 'aws-sdk';
4 | import * as uuid from 'node-uuid';
5 | import * as _ from 'lodash';
6 | import * as os from 'os';
7 |
8 | import { Transport } from 'winston';
9 | import { TransportInstance } from 'winston';
10 |
11 | const hostname = os.hostname();
12 |
13 | function datify(timestamp) {
14 | let dateTS = new Date(timestamp);
15 | let date = {
16 | year: dateTS.getFullYear(),
17 | month: dateTS.getMonth() + 1,
18 | day: dateTS.getDate(),
19 | hour: dateTS.getHours(),
20 | minute: dateTS.getMinutes(),
21 | second: dateTS.getSeconds(),
22 | millisecond: dateTS.getMilliseconds()
23 | };
24 |
25 | let keys = _.without(Object.keys(date), "year", "month", "day");
26 | let len = keys.length;
27 | for (let i = 0; i < len; i++) {
28 | let key = keys[i];
29 | if (date[key] < 10) {
30 | date[key] = "0" + date[key];
31 | }
32 | }
33 | return `${date.year}-${date.month}-${date.day} ${date.hour}:${date.minute}:${date.second}.${date.millisecond}`;
34 | }
35 |
36 | export interface DynamoDBTransportOptions {
37 | useEnvironment?: boolean;
38 | accessKeyId?: string;
39 | secretAccessKey?: string;
40 | region?: string;
41 | tableName: string;
42 | level: string;
43 | dynamoDoc?: boolean;
44 | }
45 |
46 | export interface DynamoDBTransportInstance extends TransportInstance {
47 | new (options?: DynamoDBTransportOptions): DynamoDBTransportInstance;
48 | }
49 |
50 | export class DynamoDB extends winston.Transport implements DynamoDBTransportInstance {
51 | regions: string[];
52 | name: string;
53 | level: string;
54 | db; // Type?
55 | AWS; // Type?
56 | region: string;
57 | tableName: string;
58 | dynamoDoc: boolean;
59 |
60 | constructor(options?: DynamoDBTransportOptions) {
61 | super(options);
62 |
63 | if (options == null) {
64 | options = {};
65 | }
66 | this.regions = ["us-east-1", "us-west-1", "us-west-2", "eu-west-1", "eu-central-1", "ap-northeast-1", "ap-northeast-2", "ap-southeast-1", "ap-southeast-2", "sa-east-1"];
67 | if (options.useEnvironment) {
68 | options.accessKeyId = process.env.AWS_ACCESS_KEY_ID;
69 | options.secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
70 | options.region = process.env.AWS_REGION;
71 | }
72 | if (options.accessKeyId == null) {
73 | throw new Error("need accessKeyId");
74 | }
75 | if (options.secretAccessKey == null) {
76 | throw new Error("need secretAccessKey");
77 | }
78 | if (options.region == null) {
79 | throw new Error("need region");
80 | }
81 | if (this.regions.indexOf(options.region) < 0) {
82 | throw new Error("unavailable region given");
83 | }
84 | if (options.tableName == null) {
85 | throw new Error("need tableName");
86 | }
87 | if (!options.useEnvironment) {
88 | AWS.config.update({
89 | accessKeyId: options.accessKeyId,
90 | secretAccessKey: options.secretAccessKey,
91 | region: options.region
92 | });
93 | }
94 | this.name = "dynamodb";
95 | this.level = options.level || "info";
96 | this.db = new AWS.DynamoDB();
97 | this.AWS = AWS;
98 | this.region = options.region;
99 | this.tableName = options.tableName;
100 | this.dynamoDoc = options.dynamoDoc;
101 | }
102 |
103 | log(level, msg, meta, callback) {
104 | let dynamoDocClient, params;
105 | let putCallback = (_this) => {
106 | return (err, data) => {
107 | if (err) {
108 | _this.emit("error", err);
109 | if (callback) {
110 | return callback(err, null);
111 | }
112 | } else {
113 | _this.emit("logged");
114 | if (callback) {
115 | return callback(null, "logged");
116 | }
117 | }
118 | };
119 | };
120 | putCallback(this);
121 | if (this.dynamoDoc === true) {
122 | params = {
123 | TableName: this.tableName,
124 | Item: {
125 | id: uuid.v4(),
126 | level: level,
127 | timestamp: datify(Date.now()),
128 | msg: msg,
129 | hostname: hostname
130 | }
131 | };
132 | if (!_.isEmpty(meta)) {
133 | params.Item.meta = meta;
134 | }
135 | dynamoDocClient = new this.AWS.DynamoDB.DocumentClient({
136 | service: this.db
137 | });
138 | return dynamoDocClient.put(params, putCallback);
139 | } else {
140 | params = {
141 | TableName: this.tableName,
142 | Item: {
143 | id: {
144 | "S": uuid.v4()
145 | },
146 | level: {
147 | "S": level
148 | },
149 | timestamp: {
150 | "S": datify(Date.now())
151 | },
152 | msg: {
153 | "S": msg
154 | },
155 | hostname: {
156 | "S": hostname
157 | }
158 | }
159 | };
160 | if (!_.isEmpty(meta)) {
161 | params.Item.meta = {
162 | "S": JSON.stringify(meta)
163 | };
164 | }
165 | return this.db.putItem(params, putCallback);
166 | }
167 | }
168 |
169 | }
170 |
171 | import { Transports } from 'winston';
172 | declare module "winston" {
173 | export interface Transports {
174 | DynamoDB: DynamoDB;
175 | }
176 | }
--------------------------------------------------------------------------------
/lib/winston-dynamodb.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __extends = (this && this.__extends) || function (d, b) {
3 | for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
4 | function __() { this.constructor = d; }
5 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
6 | };
7 | var winston = require('winston');
8 | var AWS = require('aws-sdk');
9 | var uuid = require('node-uuid');
10 | var _ = require('lodash');
11 | var os = require('os');
12 | var hostname = os.hostname();
13 | function datify(timestamp) {
14 | var dateTS = new Date(timestamp);
15 | var date = {
16 | year: dateTS.getFullYear(),
17 | month: dateTS.getMonth() + 1,
18 | day: dateTS.getDate(),
19 | hour: dateTS.getHours(),
20 | minute: dateTS.getMinutes(),
21 | second: dateTS.getSeconds(),
22 | millisecond: dateTS.getMilliseconds()
23 | };
24 | var keys = _.without(Object.keys(date), "year", "month", "day");
25 | var len = keys.length;
26 | for (var i = 0; i < len; i++) {
27 | var key = keys[i];
28 | if (date[key] < 10) {
29 | date[key] = "0" + date[key];
30 | }
31 | }
32 | return date.year + "-" + date.month + "-" + date.day + " " + date.hour + ":" + date.minute + ":" + date.second + "." + date.millisecond;
33 | }
34 | var DynamoDB = (function (_super) {
35 | __extends(DynamoDB, _super);
36 | function DynamoDB(options) {
37 | _super.call(this, options);
38 | if (options == null) {
39 | options = {};
40 | }
41 | this.regions = ["us-east-1", "us-west-1", "us-west-2", "eu-west-1", "eu-central-1", "ap-northeast-1", "ap-northeast-2", "ap-southeast-1", "ap-southeast-2", "sa-east-1"];
42 | if (options.useEnvironment) {
43 | options.accessKeyId = process.env.AWS_ACCESS_KEY_ID;
44 | options.secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
45 | options.region = process.env.AWS_REGION;
46 | }
47 | if (options.accessKeyId == null) {
48 | throw new Error("need accessKeyId");
49 | }
50 | if (options.secretAccessKey == null) {
51 | throw new Error("need secretAccessKey");
52 | }
53 | if (options.region == null) {
54 | throw new Error("need region");
55 | }
56 | if (this.regions.indexOf(options.region) < 0) {
57 | throw new Error("unavailable region given");
58 | }
59 | if (options.tableName == null) {
60 | throw new Error("need tableName");
61 | }
62 | if (!options.useEnvironment) {
63 | AWS.config.update({
64 | accessKeyId: options.accessKeyId,
65 | secretAccessKey: options.secretAccessKey,
66 | region: options.region
67 | });
68 | }
69 | this.name = "dynamodb";
70 | this.level = options.level || "info";
71 | this.db = new AWS.DynamoDB();
72 | this.AWS = AWS;
73 | this.region = options.region;
74 | this.tableName = options.tableName;
75 | this.dynamoDoc = options.dynamoDoc;
76 | }
77 | DynamoDB.prototype.log = function (level, msg, meta, callback) {
78 | var dynamoDocClient, params;
79 | var putCallback = function (_this) {
80 | return function (err, data) {
81 | if (err) {
82 | _this.emit("error", err);
83 | if (callback) {
84 | return callback(err, null);
85 | }
86 | }
87 | else {
88 | _this.emit("logged");
89 | if (callback) {
90 | return callback(null, "logged");
91 | }
92 | }
93 | };
94 | };
95 | putCallback(this);
96 | if (this.dynamoDoc === true) {
97 | params = {
98 | TableName: this.tableName,
99 | Item: {
100 | id: uuid.v4(),
101 | level: level,
102 | timestamp: datify(Date.now()),
103 | msg: msg,
104 | hostname: hostname
105 | }
106 | };
107 | if (!_.isEmpty(meta)) {
108 | params.Item.meta = meta;
109 | }
110 | dynamoDocClient = new this.AWS.DynamoDB.DocumentClient({
111 | service: this.db
112 | });
113 | return dynamoDocClient.put(params, putCallback);
114 | }
115 | else {
116 | params = {
117 | TableName: this.tableName,
118 | Item: {
119 | id: {
120 | "S": uuid.v4()
121 | },
122 | level: {
123 | "S": level
124 | },
125 | timestamp: {
126 | "S": datify(Date.now())
127 | },
128 | msg: {
129 | "S": msg
130 | },
131 | hostname: {
132 | "S": hostname
133 | }
134 | }
135 | };
136 | if (!_.isEmpty(meta)) {
137 | params.Item.meta = {
138 | "S": JSON.stringify(meta)
139 | };
140 | }
141 | return this.db.putItem(params, putCallback);
142 | }
143 | };
144 | return DynamoDB;
145 | }(winston.Transport));
146 | exports.DynamoDB = DynamoDB;
147 |
--------------------------------------------------------------------------------