1
+ /**
2
+ * Copyright 2016 Google Inc. All Rights Reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ 'use strict' ;
17
+
1
18
const functions = require ( 'firebase-functions' ) ,
2
- admin = require ( 'firebase-admin' ) ;
19
+ admin = require ( 'firebase-admin' ) ,
20
+ logging = require ( '@google-cloud/logging' ) ( ) ;
3
21
4
22
admin . initializeApp ( functions . config ( ) . firebase ) ;
5
23
6
24
const stripe = require ( 'stripe' ) ( functions . config ( ) . stripe . token ) ,
7
25
currency = functions . config ( ) . stripe . currency || 'USD' ;
8
26
27
+ // [START chargecustomer]
9
28
exports . createStripeCharge = functions . database . ref ( '/users/{userId}/charges/{id}' ) . onWrite ( event => {
10
29
const val = event . data . val ( ) ;
11
30
if ( val === null || val . id || val . error ) return null ;
@@ -18,10 +37,15 @@ exports.createStripeCharge = functions.database.ref('/users/{userId}/charges/{id
18
37
} ) . then ( response => {
19
38
return event . data . ref . set ( response ) ;
20
39
} , error => {
21
- return event . data . ref . child ( 'error' ) . set ( error . message ) ;
40
+ // We want to capture errors and render them in a user-friendly way, while
41
+ // still logging an exception with Stackdriver
42
+ return event . data . ref . child ( 'error' ) . set ( userFacingMessage ( error ) ) . then ( ( ) => {
43
+ return reportError ( error , { user : event . params . userId } ) ;
44
+ } ) ;
22
45
}
23
46
) ;
24
47
} ) ;
48
+ // [END chargecustomer]]
25
49
26
50
exports . createStripeCustomer = functions . auth . user ( ) . onCreate ( event => {
27
51
const data = event . data ;
@@ -41,3 +65,45 @@ exports.cleanupUser = functions.auth.user().onDelete(event => {
41
65
return admin . database ( ) . ref ( `/stripe_customers/${ event . data . uid } ` ) . remove ( ) ;
42
66
} ) ;
43
67
} ) ;
68
+
69
+ // [START reporterror]
70
+ function reportError ( err , context = { } ) {
71
+ // This is the name of the StackDriver log stream that will receive the log
72
+ // entry. This name can be any valid log stream name, but must contain "err"
73
+ // in order for the error to be picked up by StackDriver Error Reporting.
74
+ const logName = 'errors' ;
75
+ const log = logging . log ( logName ) ;
76
+
77
+ const metadata = {
78
+ // https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/MonitoredResource
79
+ resource : {
80
+ type : 'cloud_function' ,
81
+ labels : { function_name : process . env . FUNCTION_NAME }
82
+ }
83
+ } ;
84
+
85
+ // https://cloud.google.com/error-reporting/reference/rest/v1beta1/ErrorEvent
86
+ const errorEvent = {
87
+ message : err . stack ,
88
+ serviceContext : {
89
+ service : process . env . FUNCTION_NAME ,
90
+ resourceType : 'cloud_function'
91
+ } ,
92
+ context : context
93
+ } ;
94
+
95
+ // Write the error log entry
96
+ return new Promise ( ( resolve , reject ) => {
97
+ log . write ( log . entry ( metadata , errorEvent ) , error => {
98
+ if ( error ) { reject ( error ) ; }
99
+ resolve ( ) ;
100
+ } ) ;
101
+ } ) ;
102
+ }
103
+ // [END reporterror]
104
+
105
+ function userFacingMessage ( error ) {
106
+ return error . type ? error . message : 'An error occurred, developers have been alerted' ;
107
+ }
108
+
109
+
0 commit comments