Skip to content

Commit ae3b6a6

Browse files
authored
Feature/stackdriver credentials object (#89)
* added support passing credentials object parameter to Stackdriver * updated API doc with object credentials * added credentials object into cli * updated cli and api docs * fix
1 parent 1c7fa01 commit ae3b6a6

File tree

7 files changed

+77
-9
lines changed

7 files changed

+77
-9
lines changed

docs/API.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ const writeStream = stackdriver.createWriteStream({
3535

3636
#### credentials
3737

38-
Type: `String` *(optional)*
38+
Type: `String` or `{ client_email: String, private_key: String }` *(optional)*
39+
40+
Full path to the JSON file containing the Google Service Credentials,
41+
you can also use an object parameter with the client_email and the private_key instead of the path. Defaults to the GOOGLE_APPLICATION_CREDENTIALS environment variable. At least one has to be available.
3942

40-
Full path to the JSON file containing the Google Service Credentials. Defaults to the GOOGLE_APPLICATION_CREDENTIALS environment variable. At least one has to be available.
4143

4244
#### projectId
4345

docs/CLI.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ You can pass the following options via cli arguments:
2222
| ------------- | ------------ |-------------|
2323
| -V | --version | Output the version number |
2424
| -p | --project <project> | Your Google Cloud Platform project ID (or use env var PROJECT_ID) |
25-
| -c | --credentials <credentials> | The file path of the JSON file that contains your service account key (or use env var GOOGLE_APPLICATION_CREDENTIALS) |
25+
| -c | --credentials <credentials> | The file path of the JSON file that contains your service account key (or use env var GOOGLE_APPLICATION_CREDENTIALS). you can also use clientEmail and privateKey instead of the path. |
26+
| -e | --clientEmail <email> | Client email, part of credentials object provided by Google |
27+
| -g | --privateKey <googleKey> | Private key, part of credentials object provided by Google. |
2628
| -k | --key <key:customKey> | Repeatable `key:customKey` pairs for custom keys (see [API docs](./API.md#keys))
2729
| -n | --logName | The resource to send logs to. Defaults to `{"type": "global"}`.
2830
| -r | --resource <resourcejson> | Resource to send the logs to, input in JSON (see [API docs](./API.md#resource))

pino-stackdriver.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ declare namespace PinoStackdriver {
55
* Full path to the JSON file containing the Google Service Credentials.
66
* Defaults to GOOGLE_APPLICATION_CREDENTIALS environment variable.
77
*/
8-
credentials?: string;
8+
credentials?: string | {client_email: string, private_key:string};
99

1010
/**
1111
* The name of the project.

src/cli.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,22 @@ function collect (value, previous) {
1313
function main () {
1414
program
1515
.version(pkg.version)
16+
.option('-e, --clientEmail <email>', 'Client email, part of credentials object provided by Google')
17+
.option('-g, --privateKey <googleKey>', 'Private key, part of credentials object provided by Google')
1618
.option('-c, --credentials <credentials>', 'The file path of the JSON file that contains your service account key')
1719
.option('-p, --project <project>', 'Your Google Cloud Platform project ID')
1820
.option('-k, --key <key:customKey>', 'Customize additional data to include in log metadata', collect, [])
1921
.option('-n, --logName <name>', 'The name of the log. Defaults to "pino_log".')
2022
.option('-r, --resource <resource>', 'The resource to send logs to. Defaults to { "type": "global" }', JSON.parse, { type: 'global' })
21-
.action(({ credentials, project, key, logName, resource }) => {
23+
.action(({ credentials, project, key, logName, resource, clientEmail, privateKey }) => {
2224
try {
23-
const _credentials = credentials || process.env.GOOGLE_APPLICATION_CREDENTIALS
25+
if (!clientEmail ^ !privateKey) throw Error('Client email or google private key is missing.')
26+
if (credentials && (clientEmail || privateKey)) {
27+
throw Error('Use client email and google private key or credentials, no both!')
28+
}
29+
const _credentials = (clientEmail && privateKey)
30+
? { client_email: clientEmail, private_key: privateKey }
31+
: (credentials || process.env.GOOGLE_APPLICATION_CREDENTIALS)
2432
if (!process.env.PROJECT_ID && !project) { throw Error('Project is missing.') }
2533
const _project = project || process.env.PROJECT_ID
2634

src/stackdriver.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,22 @@ module.exports.toLogEntryStream = function (options = {}) {
8686

8787
module.exports.toStackdriverStream = function (options = {}) {
8888
const { logName, projectId, credentials, fallback } = options
89-
if (process.env.GOOGLE_APPLICATION_CREDENTIALS || credentials) {
90-
process.env.GOOGLE_APPLICATION_CREDENTIALS = process.env.GOOGLE_APPLICATION_CREDENTIALS || credentials
91-
}
9289
if (!projectId) { throw Error('The "projectId" argument is missing') }
9390
const opt = {
9491
logName: logName || 'pino_log',
9592
projectId,
9693
scopes: ['https://www.googleapis.com/auth/logging.write'],
9794
fallback
9895
}
96+
97+
if (typeof credentials === 'object' && credentials !== null) {
98+
opt.credentials = credentials
99+
} else {
100+
if (process.env.GOOGLE_APPLICATION_CREDENTIALS || credentials) {
101+
process.env.GOOGLE_APPLICATION_CREDENTIALS = process.env.GOOGLE_APPLICATION_CREDENTIALS || credentials
102+
}
103+
}
104+
99105
const log = new Logging(opt).log(opt.logName)
100106
const writableStream = new stream.Writable({
101107
objectMode: true,

test/cli.test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,39 @@ test('pipes data to output', (t) => {
108108
app.kill()
109109
})
110110
})
111+
112+
test('throws on Client email or google private key is missing', t => {
113+
t.plan(1)
114+
delete process.env.GOOGLE_APPLICATION_CREDENTIALS
115+
const app = spawn('node', [appPath, '-e', 'email@example.com', '-p', 'project-id'])
116+
app.stdout.on('data', (data) => {
117+
const msg = data.toString()
118+
const res = (msg.indexOf('Client email or google private key is missing.') >= 0)
119+
t.ok(res)
120+
app.kill()
121+
})
122+
})
123+
124+
test('throws on use client email and google private key or credentials', t => {
125+
t.plan(1)
126+
delete process.env.GOOGLE_APPLICATION_CREDENTIALS
127+
const app = spawn('node', [appPath, '-c', './credentials.json', '-e', 'email@example.com', '-g', 'private-key', '-p', 'project-id'])
128+
app.stdout.on('data', (data) => {
129+
const msg = data.toString()
130+
const res = (msg.indexOf('Use client email and google private key or credentials, no both!') >= 0)
131+
t.ok(res)
132+
app.kill()
133+
})
134+
})
135+
136+
test('works passing object credentials', t => {
137+
t.plan(1)
138+
delete process.env.GOOGLE_APPLICATION_CREDENTIALS
139+
const app = spawn('node', [appPath, '-e', 'email@example.com', '-g', 'private-key', '-p', 'project-id'])
140+
app.stdout.on('data', (data) => {
141+
const msg = data.toString()
142+
const res = (msg.indexOf('logging') >= 0)
143+
t.ok(res)
144+
app.kill()
145+
})
146+
})

test/stackdriver.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,17 @@ test('transforms log entry message field', t => {
233233
const entry = tested.toLogEntry(log)
234234
t.ok(entry.data.message === 'Message')
235235
})
236+
237+
test('logs to stackdriver with an object credentials', t => {
238+
t.plan(1)
239+
const credentials = { client_email: 'fakeEmail', private_key: 'fakeKey' }
240+
const projectId = 'test-project'
241+
242+
const writeStream = tested.toStackdriverStream({ credentials, projectId })
243+
writeStream.on('finish', () => {
244+
t.ok(true)
245+
})
246+
const entry = { meta: { resource: { type: 'global' }, severity: 'info' }, data: { message: 'Info message' } }
247+
const readStream = helpers.readStreamTest([entry])
248+
readStream.pipe(writeStream)
249+
})

0 commit comments

Comments
 (0)