2
0

metrics.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import { Meteor } from 'meteor/meteor';
  2. import Users from '../users';
  3. function acceptedIpAddress(ipAddress) {
  4. const trustedIpAddress = process.env.WEKAN_METRICS_ACCEPTED_IP_ADDRESS;
  5. return (
  6. trustedIpAddress !== undefined &&
  7. trustedIpAddress.split(',').includes(ipAddress)
  8. );
  9. }
  10. const getBoardTitleWithMostActivities = (dateWithXdaysAgo, nbLimit) => {
  11. return Promise.await(
  12. Activities.rawCollection()
  13. .aggregate([
  14. {
  15. $match: { modifiedAt: { $gte: dateWithXdaysAgo }}
  16. },
  17. {
  18. $group: { _id: '$boardId', count: { $sum: 1 } }
  19. },
  20. {
  21. $sort: { count: -1 }
  22. },
  23. {
  24. $lookup: { from: 'boards', localField: '_id', foreignField: '_id', as: 'lookup'}
  25. },
  26. {
  27. $project: { "lookup.title":1, "count":1}
  28. }])
  29. .limit(nbLimit).toArray()
  30. );
  31. };
  32. const getBoards = (boardIds) => {
  33. return Boards.find({ _id: { $in: boardIds } }).fetch();
  34. };
  35. Meteor.startup(() => {
  36. WebApp.connectHandlers.use('/metrics', (req, res, next) => {
  37. try {
  38. const ipAddress =
  39. req.headers['x-forwarded-for'] || req.socket.remoteAddress;
  40. // if(process.env.TRUST_PROXY_FORXARD)
  41. // {
  42. // const ipAddress = req.headers['x-forwarded-for'] || req.socket.remoteAddress
  43. // }else{
  44. // const ipAddress = req.socket.remoteAddress
  45. // }
  46. // List of trusted ip adress will be found in environment variable "WEKAN_METRICS_ACCEPTED_IP_ADDRESS" (separeted with commas)
  47. if (acceptedIpAddress(ipAddress)) {
  48. let metricsRes = '';
  49. let resCount = 0;
  50. //connected users
  51. metricsRes += '# Number of connected users\n';
  52. // Get number of connected user by using meteor socketJs
  53. const allOpenedSockets = Meteor.server.stream_server.open_sockets;
  54. let connectedUserIds = [];
  55. allOpenedSockets.forEach(
  56. (socket) =>
  57. socket._meteorSession.userId !== null &&
  58. connectedUserIds.push(socket._meteorSession.userId),
  59. );
  60. resCount = connectedUserIds.length; // KPI 1
  61. metricsRes += 'wekan_connectedUsers ' + resCount + '\n';
  62. //registered users
  63. metricsRes += '# Number of registered users\n';
  64. // Get number of registered user
  65. resCount = Users.find({}).count(); // KPI 2
  66. metricsRes += 'wekan_registeredUsers ' + resCount + '\n';
  67. resCount = 0;
  68. //board numbers
  69. metricsRes += '# Number of registered boards\n';
  70. // Get number of registered boards
  71. resCount = Boards.find({ archived: false, type: 'board' }).count(); // KPI 3
  72. metricsRes += 'wekan_registeredboards ' + resCount + '\n';
  73. resCount = 0;
  74. //board numbers by registered users
  75. metricsRes += '# Number of registered boards by registered users\n';
  76. // Get number of registered boards by registered users
  77. resCount =
  78. Boards.find({ archived: false, type: 'board' }).count() /
  79. Users.find({}).count(); // KPI 4
  80. metricsRes +=
  81. 'wekan_registeredboardsBysRegisteredUsers ' + resCount + '\n';
  82. resCount = 0;
  83. //board numbers with only one member
  84. metricsRes += '# Number of registered boards\n';
  85. // Get board numbers with only one member
  86. resCount = Boards.find({
  87. archived: false,
  88. type: 'board',
  89. members: { $size: 1 },
  90. }).count(); // KPI 5
  91. metricsRes +=
  92. 'wekan_registeredboardsWithOnlyOneMember ' + resCount + '\n';
  93. resCount = 0;
  94. // KPI 6 : - store last login date
  95. // KPI 6 = count where date of last connection > x days
  96. // Cutting in label since 5 days / 10 days / 20 days / 30 days
  97. //Number of users with last connection dated 5 days ago
  98. metricsRes +=
  99. '# Number of users with last connection dated 5 days ago\n';
  100. // Get number of users with last connection dated 5 days ago
  101. let xdays = 5;
  102. let dateWithXdaysAgo = new Date(
  103. new Date() - xdays * 24 * 60 * 60 * 1000,
  104. );
  105. resCount = Users.find({
  106. lastConnectionDate: { $gte: dateWithXdaysAgo },
  107. }).count(); // KPI 5
  108. metricsRes +=
  109. 'wekan_usersWithLastConnectionDated5DaysAgo ' + resCount + '\n';
  110. resCount = 0;
  111. metricsRes +=
  112. '# Number of users with last connection dated 10 days ago\n';
  113. // Get number of users with last connection dated 10 days ago
  114. xdays = 10;
  115. dateWithXdaysAgo = new Date(new Date() - xdays * 24 * 60 * 60 * 1000);
  116. resCount = Users.find({
  117. lastConnectionDate: { $gte: dateWithXdaysAgo },
  118. }).count(); // KPI 5
  119. metricsRes +=
  120. 'wekan_usersWithLastConnectionDated10DaysAgo ' + resCount + '\n';
  121. resCount = 0;
  122. metricsRes +=
  123. '# Number of users with last connection dated 20 days ago\n';
  124. // Get number of users with last connection dated 20 days ago
  125. xdays = 20;
  126. dateWithXdaysAgo = new Date(new Date() - xdays * 24 * 60 * 60 * 1000);
  127. resCount = Users.find({
  128. lastConnectionDate: { $gte: dateWithXdaysAgo },
  129. }).count(); // KPI 5
  130. metricsRes +=
  131. 'wekan_usersWithLastConnectionDated20DaysAgo ' + resCount + '\n';
  132. resCount = 0;
  133. metricsRes +=
  134. '# Number of users with last connection dated 30 days ago\n';
  135. // Get number of users with last connection dated 20 days ago
  136. xdays = 30;
  137. dateWithXdaysAgo = new Date(new Date() - xdays * 24 * 60 * 60 * 1000);
  138. resCount = Users.find({
  139. lastConnectionDate: { $gte: dateWithXdaysAgo },
  140. }).count(); // KPI 5
  141. metricsRes +=
  142. 'wekan_usersWithLastConnectionDated30DaysAgo ' + resCount + '\n';
  143. resCount = 0;
  144. // TO DO:
  145. // connection average: ((disconnection date - last connection date) + (last average)) / 2
  146. // KPI 7 : sum of connection average / number of users (ignore users with 0 average)
  147. metricsRes +=
  148. '# Top 10 boards with most activities dated 30 days ago\n';
  149. //Get top 10 table with most activities in current month
  150. const boardTitleWithMostActivities = getBoardTitleWithMostActivities(
  151. dateWithXdaysAgo,
  152. xdays,
  153. );
  154. const boardWithMostActivities = boardTitleWithMostActivities.map(
  155. (board) => board.lookup[0].title,
  156. );
  157. boardWithMostActivities.forEach((title, index) => {
  158. metricsRes +=
  159. `wekan_top10BoardsWithMostActivities{n="${title}"} ${
  160. index + 1
  161. }` + '\n';
  162. });
  163. res.writeHead(200); // HTTP status
  164. res.end(metricsRes);
  165. } else {
  166. res.writeHead(401); // HTTP status
  167. res.end(
  168. 'IpAddress: ' +
  169. ipAddress +
  170. ' is not authorized to perform this action !!\n',
  171. );
  172. }
  173. } catch (e) {
  174. res.writeHead(500); // HTTP status
  175. res.end(e.toString());
  176. }
  177. });
  178. });