« index

Coverage for /Users/yunong/workspace/node-restify/lib/plugins/audit.js : 93%

110 lines | 103 run | 7 missing | 1 partial | 12 blocks | 6 blocks run | 6 blocks missing

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

  // Copyright 2012 Mark Cavage, Inc.  All rights reserved.
  
  var assert = require('assert-plus');
  var bunyan = require('bunyan');
  
  var HttpError = require('../errors').HttpError;
  
  
  ///--- API
  
  /**
   * Returns a Bunyan audit logger suitable to be used in a server.on('after')
   * event.  I.e.:
   *
   * server.on('after', restify.auditLogger({ log: myAuditStream }));
   *
   * This logs at the INFO level.
   *
   * @param {Object} options at least a bunyan logger (log).
   * @return {Function} to be used in server.after.
   */
  function auditLogger(options) {
      assert.object(options, 'options');
      assert.object(options.log, 'options.log');
      var errSerializer = bunyan.stdSerializers.err;
  
      if (options.log.serializers && options.log.serializers.err) {
          errSerializer = options.log.serializers.err;
      }
  
      var log = options.log.child({
          audit: true,
          serializers: {
              err: errSerializer,
              req: function auditRequestSerializer(req) {
                  if (!req)
                      return (false);
  
                  var timers = {};
                  (req.timers || []).forEach(function (time) {
                      var t = time.time;
                      var _t = Math.floor((1000000 * t[0]) +
                          (t[1] / 1000));
                      timers[time.name] = _t;
                  });
                  return ({
                      method: req.method,
                      url: req.url,
                      headers: req.headers,
                      httpVersion: req.httpVersion,
                      trailers: req.trailers,
                      version: req.version(),
                      body: options.body === true ?
                          req.body : undefined,
                      timers: timers
                  });
              },
              res: function auditResponseSerializer(res) {
                  if (!res)
                      return (false);
  
  
                  var body;
                  if (options.body === true) {
                      if (res._body instanceof HttpError) {
                          body = res._body.body;
                      } else {
                          body = res._body;
                      }
                  }
  
                  return ({
                      statusCode: res.statusCode,
                      headers: res._headers,
                      trailer: res._trailer || false,
                      body: body
                  });
              }
          }
      });
  
      function audit(req, res, route, err) {
          var latency = res.get('Response-Time');
          if (typeof (latency) !== 'number')
              latency = Date.now() - req._time;
  
          var obj = {
              remoteAddress: req.connection.remoteAddress,
              remotePort: req.connection.remotePort,
              req_id: req.getId(),
              req: req,
              res: res,
              err: err,
              latency: latency,
              secure: req.secure,
              _audit: true
          };
  
          log.info(obj, 'handled: %d', res.statusCode);
  
          return (true);
      }
  
      return (audit);
  }
  
  
  ///-- Exports
  
  module.exports = auditLogger;
« index | cover.io