logster 2.4.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0b7d537afb560db43baeed0d1de845c84df83b499fe6fd84f8a803133b9219d
4
- data.tar.gz: 36d7b21799023ce9af8005a115d60809ea606d5170ee4a908ad3764ed9a49a59
3
+ metadata.gz: 32d46ec6061a8b58d50146ab27c3185f3964680207f0a6ad783ad3122aa44d2a
4
+ data.tar.gz: abf94ecdefb382f60606e0d94cffa9dae77a64eda8f124f7a1c6c9295be688bd
5
5
  SHA512:
6
- metadata.gz: 865760766f7429c9610e66042f6d463bf3423a7f73f07c78eec36ee815fa20883870f1300a234be886731b5da6716a7ef50d6ceecc14b190b01e2385ae32e71f
7
- data.tar.gz: 3f2ef09d8b21224b1d90af7a1775f8fbcbb7205e7b6315bba25e605d706c777c604361ec011b60a1814a8347eab7166c95e8f1324953564d27d8121303d60691
6
+ metadata.gz: b0a40b769c195f36fa14bc856efe6490653113b57f65b0b07875a648d1ffaa98f26343cbed2f6d688402ef83c63b2ad142e8d81624f25f043f4d0f84be0d8f30
7
+ data.tar.gz: 428f7b1e3577f16c65752ddeca5f8004858f204e97fdba496816df532308201fdd415e8edf2b081bcb3090dd3bc0f2cd59f6778561af3b5a16f6f4d6163320d1
@@ -1,5 +1,13 @@
1
1
  # CHANGELOG
2
2
 
3
+ - 2019-10-17: 2.4.1
4
+
5
+ - PERF: Debounce search field so it doesn't fire a search query at every keystroke.
6
+ - PERF: Disallow search terms that are fewer than 2 characters long.
7
+ - PERF: Bypass refresh cycle if previous cycle hasn't finished.
8
+ - PERF: Defer sending message envs to client until the user requests them.
9
+ - PERF: Cap message size to 60,000 bytes by default.
10
+
3
11
  - 2019-10-10: 2.4.0
4
12
 
5
13
  - FEATURE: Allow having retroactive affect when adding suppression patterns
data/README.md CHANGED
@@ -43,6 +43,8 @@ Logster can be configured using `Logster.config`:
43
43
  - `Logster.config.enable_js_error_reporting` : enable js error reporting from clients
44
44
  - `Logster.config.rate_limit_error_reporting` : controls automatic 1 minute rate limiting for JS error reporting.
45
45
  - `Logster.config.web_title` : `<title>` tag for logster error page.
46
+ - `Logster.config.enable_custom_patterns_via_ui` : enables a setting page that allows adding suppression patterns via the UI.
47
+ - `Logster.config.maximum_message_size_bytes` : specifiy a size in bytes that a message cannot exceed. Note this isn't 100% accurate, meaning a message may still grow above the limit, but it shouldn't grow by more tha, say, 2000 bytes.
46
48
 
47
49
  ### Tracking Error Rate
48
50
  Logster allows you to register a callback when the rate of errors has exceeded
@@ -1,8 +1,8 @@
1
1
  "use strict"
2
2
  define("client-app/app",["exports","client-app/resolver","ember-load-initializers","client-app/config/environment"],function(e,t,n,a){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
3
3
  var s=Ember.Application.extend({modulePrefix:a.default.modulePrefix,podModulePrefix:a.default.podModulePrefix,Resolver:t.default});(0,n.default)(s,a.default.modulePrefix)
4
- var r=s
5
- e.default=r}),define("client-app/components/actions-menu",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
4
+ var i=s
5
+ e.default=i}),define("client-app/components/actions-menu",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
6
6
  var t=Ember.Component.extend({showMenu:!1,tagName:"span",init:function(){this._super.apply(this,arguments),this.bindingFunction=this.bindingFunction.bind(this)},bindingFunction:function(e){var t=this.$()[0]
7
7
  Em.$.contains(t,e.target)||t===e.target||this.set("showMenu",!1)},bindDocument:Ember.observer("showMenu",function(){var e=Em.$(document)
8
8
  this.get("showMenu")?e.on("click",this.get("bindingFunction")):e.off("click",this.get("bindingFunction"))}),willDestroyElement:function(){this._super.apply(this,arguments),Em.$(document).off("click",this.get("bindingFunction"))},actions:{expandMenu:function(){this.toggleProperty("showMenu")},share:function(){this.share()}}})
@@ -15,20 +15,20 @@ this.set("current",this.get("current")+t)},bigJump:function(e){var t="back"===e?
15
15
  this.set("current",t)}}})
16
16
  e.default=a}),define("client-app/components/message-info",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
17
17
  var t=Ember.Component.extend({buttons:Ember.computed("currentMessage.{canSolve,protected}",function(){var e=this.get("currentMessage.canSolve"),t=this.get("currentMessage.protected"),n=[]
18
- return!t&&e&&n.push({klass:"solve",action:"solve",icon:"check-square-o",label:"Solve",danger:!0}),t?n.push({klass:"unprotect",action:"unprotect",icon:"unlock",label:"Unprotect"}):n.push({klass:"remove",action:"remove",icon:"trash-o",label:"Remove",danger:!0},{klass:"protect",action:"protect",icon:"lock",label:"Protect"}),n}),actions:{protect:function(){this.get("currentMessage").protect()},unprotect:function(){this.get("currentMessage").unprotect()},remove:function(){this.removeMessage(this.get("currentMessage"))},solve:function(){this.solveMessage(this.get("currentMessage"))},share:function(){window.location.pathname=this.get("currentMessage.shareUrl")}}})
18
+ return!t&&e&&n.push({klass:"solve",action:"solve",icon:"check-square-o",label:"Solve",danger:!0}),t?n.push({klass:"unprotect",action:"unprotect",icon:"unlock",label:"Unprotect"}):n.push({klass:"remove",action:"remove",icon:"trash-o",label:"Remove",danger:!0},{klass:"protect",action:"protect",icon:"lock",label:"Protect"}),n}),actions:{tabChanged:function(e){this.onTabChange&&this.onTabChange(e)},protect:function(){this.get("currentMessage").protect()},unprotect:function(){this.get("currentMessage").unprotect()},remove:function(){this.removeMessage(this.get("currentMessage"))},solve:function(){this.solveMessage(this.get("currentMessage"))},share:function(){window.location.pathname=this.get("currentMessage.shareUrl")}}})
19
19
  e.default=t}),define("client-app/components/message-row",["exports"],function(e){var t,n
20
20
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
21
- var a=Ember.Component.extend({tagName:"div",classNameBindings:["model.rowClass",":message-row","model.selected:selected"],click:function(){this.selectedMessage(this.get("model"))},willInsertElement:function(){if(!t){var e=Em.$("#top-panel"),a=e.scrollTop(),s=e.height(),r=e[0].scrollHeight
22
- n=r-20<s+a,t=!0}},didInsertElement:function(){var e=Em.$("#top-panel")
21
+ var a=Ember.Component.extend({tagName:"div",classNameBindings:["model.rowClass",":message-row","model.selected:selected"],click:function(){this.selectedMessage(this.get("model"))},willInsertElement:function(){if(!t){var e=Em.$("#top-panel"),a=e.scrollTop(),s=e.height(),i=e[0].scrollHeight
22
+ n=i-20<s+a,t=!0}},didInsertElement:function(){var e=Em.$("#top-panel")
23
23
  Em.run.next(function(){t=!1,n&&(n=!1,e.scrollTop(e[0].scrollHeight-e.height()))})}})
24
24
  e.default=a}),define("client-app/components/panel-resizer",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
25
25
  var t=["touchmove","mousemove"],n=["touchend","mouseup"],a=["touchstart","mousedown"],s=Ember.Component.extend({classNames:["divider"],divideView:function(e,t){var n=t||Em.$(window),a=n.height(),s=n.height()-e
26
26
  e<100||e+170>a||(this.divider.css("bottom",s-5),this.events.trigger("panelResized",s))},didInsertElement:function(){var e=this
27
27
  this.divider=Em.$(".divider")
28
- var s=Em.$(window),r=!1,i=function(t){r&&e.divideView(t.clientY||t.touches&&t.touches[0]&&t.touches[0].clientY,s)},o=function a(){Em.$("#overlay").remove(),r=!1,localStorage&&(localStorage.logster_divider_bottom=parseInt(e.divider.css("bottom"),10))
28
+ var s=Em.$(window),i=!1,r=function(t){i&&e.divideView(t.clientY||t.touches&&t.touches[0]&&t.touches[0].clientY,s)},o=function a(){Em.$("#overlay").remove(),i=!1,localStorage&&(localStorage.logster_divider_bottom=parseInt(e.divider.css("bottom"),10))
29
29
  var s=Em.$(document)
30
- t.forEach(function(e){return s.unbind(e,i)}),n.forEach(function(e){return s.unbind(e,a)})}
31
- this.divider.on(a.join(" "),function(e){e.preventDefault(),Em.$("<div id='overlay'></div>").appendTo(Em.$("body")),r=!0,Em.$(document).on(t.join(" "),_.throttle(i,25)).on(n.join(" "),o)}),Em.run.next(function(){var t=localStorage&&localStorage.logster_divider_bottom||300,n=s.height()-parseInt(t,10)
30
+ t.forEach(function(e){return s.unbind(e,r)}),n.forEach(function(e){return s.unbind(e,a)})}
31
+ this.divider.on(a.join(" "),function(e){e.preventDefault(),Em.$("<div id='overlay'></div>").appendTo(Em.$("body")),i=!0,Em.$(document).on(t.join(" "),_.throttle(r,25)).on(n.join(" "),o)}),Em.run.next(function(){var t=localStorage&&localStorage.logster_divider_bottom||300,n=s.height()-parseInt(t,10)
32
32
  e.divideView(n,s)})},willDestroyElement:function(){Em.$(".divider").off(a.join(" "))}})
33
33
  e.default=s}),define("client-app/components/patterns-list",["exports","@babel/runtime/helpers/esm/toConsumableArray","client-app/models/pattern-item","client-app/lib/utilities"],function(e,t,n,a){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
34
34
  var s=Ember.Component.extend({immutable:Ember.computed.not("mutable"),init:function(){this._super.apply(this,arguments),this.get("patterns.length")<1&&this.get("mutable")&&this.send("create")},allPatterns:Ember.computed("patterns.[]","newPatterns.[]",function(){var e=this.get("patterns"),n=this.get("newPatterns")||[]
@@ -43,25 +43,27 @@ t&&t[e](this)},didInsertElement:function(){this.invokeParent("addTab"),this.get(
43
43
  e.default=t}),define("client-app/components/tabbed-section",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
44
44
  var t=Ember.Component.extend({tabs:Em.A(),selectTab:function(e){if(e.get("isLink"))this.triggerAction(e.get("action"))
45
45
  else{var t=this.get("selected")
46
- t&&t.set("active",!1),this.set("selected",e),e.set("active",!0)}},addTab:function(e){this.get("tabs").addObject(e),this.get("selected")||e.get("isLink")||this.selectTab(e)},removeTab:function(e){this.get("selected")===e&&this.set("selected",null),this.get("tabs").removeObject(e)}})
46
+ t&&t.set("active",!1),this.set("selected",e),e.set("active",!0),this.onTabChange(e.name)}},addTab:function(e){this.get("tabs").addObject(e),this.get("selected")||e.get("isLink")||this.selectTab(e)},removeTab:function(e){this.get("selected")===e&&this.set("selected",null),this.get("tabs").removeObject(e)}})
47
47
  e.default=t}),define("client-app/components/time-formatter",["exports","client-app/lib/utilities"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
48
48
  var n=Ember.Component.extend({tagName:"span",classNames:"auto-update-time",attributeBindings:["dataTimestamp:data-timestamp","title"],title:Ember.computed(function(){return this.get("moment").format()}),dataTimestamp:Ember.computed(function(){return this.get("timestamp")}),moment:Ember.computed(function(){return moment(this.get("timestamp"))}),time:Ember.computed("timestamp",function(){return(0,t.formatTime)(this.get("timestamp"))})})
49
49
  e.default=n}),define("client-app/components/update-time",["exports","client-app/lib/utilities"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
50
50
  var n=Ember.Component.extend({didInsertElement:function(){Em.run.later(function e(){Em.$(".auto-update-time").each(function(){var e=parseInt(this.getAttribute("data-timestamp"),10),n=(0,t.formatTime)(e)
51
51
  n!==this.innerText&&(this.innerText=n)}),Em.run.later(e,6e4)},6e4)}})
52
52
  e.default=n}),define("client-app/controllers/index",["exports","client-app/lib/utilities","client-app/lib/preload"],function(e,t,n){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
53
- var a=Ember.Controller.extend({showDebug:!0,showInfo:!0,showWarn:!0,showErr:!0,showFatal:!0,search:"",currentMessage:Em.computed.alias("model.currentMessage"),showSettings:Ember.computed(function(){return n.default.get("patterns_enabled")}),resizePanels:function(e){Em.$("#bottom-panel").css("height",e-13),Em.$("#top-panel").css("bottom",e+12)},actionsInMenu:Ember.computed(function(){return this.site.isMobile}),actions:{expandMessage:function(e){e.expand()},selectMessage:function(e){var t=this.get("currentMessage")
54
- t&&t.set("selected",!1),e.set("selected",!0),this.set("currentMessage",e)},showMoreBefore:function(){this.get("model").showMoreBefore()},loadMore:function(){return this.get("model").loadMore()},clear:function(){var e=this
53
+ var a=Ember.Controller.extend({showDebug:!0,showInfo:!0,showWarn:!0,showErr:!0,showFatal:!0,search:"",currentMessage:Em.computed.alias("model.currentMessage"),currentTab:null,showSettings:Ember.computed(function(){return n.default.get("patterns_enabled")}),resizePanels:function(e){Em.$("#bottom-panel").css("height",e-13),Em.$("#top-panel").css("bottom",e+12)},actionsInMenu:Ember.computed(function(){return this.site.isMobile}),fetchEnv:function(){var e=this,n=this.get("currentMessage")
54
+ if(n)return this.set("loadingEnv",!0),(0,t.ajax)("/fetch-env/".concat(n.key,".json")).then(function(e){return n.set("env",e)}).always(function(){return e.set("loadingEnv",!1)})},actions:{expandMessage:function(e){e.expand()},selectMessage:function(e){var t=this.get("currentMessage")
55
+ t&&t.set("selected",!1),e.set("selected",!0),this.setProperties({currentMessage:e,loadingEnv:!1}),e.env||"env"!==this.currentTab||this.fetchEnv()},tabChanged:function(e){this.setProperties({currentTab:e,loadingEnv:!1}),"env"!==e||this.get("currentMessage.env")||this.fetchEnv()},showMoreBefore:function(){this.get("model").showMoreBefore()},loadMore:function(){return this.get("model").loadMore()},clear:function(){var e=this
55
56
  confirm("Clear the logs?\n\nCancel = No, OK = Clear")&&(0,t.ajax)("/clear",{type:"POST"}).then(function(){e.get("model").reload()})},removeMessage:function(e){this.get("model").destroy(e)},solveMessage:function(e){this.get("model").solve(e)}},updateSelectedMessage:function(){var e=this.get("currentMessage.key"),t=this.get("model.messages")
56
57
  if(e&&t){var n=t.find(function(t){return t.key===e})
57
58
  n?n.set("selected",!0):this.set("currentMessage",null)}},filter:Ember.computed("showDebug","showInfo","showWarn","showErr","showFatal",function(){var e=this,t=[]
58
59
  return["Debug","Info","Warn","Err","Fatal"].forEach(function(n,a){e.get("show".concat(n))&&t.push(a)}),t.push(5),t}),filterChanged:Ember.observer("filter.length",function(){var e=this,t=this.get("filter"),n=this.get("model")
59
- n.set("filter",t),t&&this.get("initialized")&&n.reload().then(function(){return e.updateSelectedMessage()})}),searchChanged:Ember.observer("search",function(){var e=this,t=this.get("search"),n=this.get("model")
60
- n.set("search",t),this.get("initialized")&&n.reload().then(function(){return e.updateSelectedMessage()})})})
60
+ n.set("filter",t),t&&this.get("initialized")&&n.reload().then(function(){return e.updateSelectedMessage()})}),doSearch:function(e){var t=this,n=this.get("model")
61
+ n.set("search",e),this.get("initialized")&&n.reload().then(function(){return t.updateSelectedMessage()})},searchChanged:Ember.observer("search",function(){var e=this.search,t=e&&e.length
62
+ t&&1===t||Ember.run.debounce(this,this.doSearch,e,250)})})
61
63
  e.default=a}),define("client-app/controllers/show",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
62
64
  var t=Ember.Controller.extend({actions:{protect:function(){this.get("model").protect()},unprotect:function(){this.get("model").unprotect()}}})
63
- e.default=t}),define("client-app/helpers/app-version",["exports","client-app/config/environment","ember-cli-app-version/utils/regexp"],function(e,t,n){function a(e){var a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},s=t.default.APP.version,r=a.versionOnly||a.hideSha,i=a.shaOnly||a.hideVersion,o=null
64
- return r&&(a.showExtended&&(o=s.match(n.versionExtendedRegExp)),o||(o=s.match(n.versionRegExp))),i&&(o=s.match(n.shaRegExp)),o?o[0]:s}Object.defineProperty(e,"__esModule",{value:!0}),e.appVersion=a,e.default=void 0
65
+ e.default=t}),define("client-app/helpers/app-version",["exports","client-app/config/environment","ember-cli-app-version/utils/regexp"],function(e,t,n){function a(e){var a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},s=t.default.APP.version,i=a.versionOnly||a.hideSha,r=a.shaOnly||a.hideVersion,o=null
66
+ return i&&(a.showExtended&&(o=s.match(n.versionExtendedRegExp)),o||(o=s.match(n.versionRegExp))),r&&(o=s.match(n.shaRegExp)),o?o[0]:s}Object.defineProperty(e,"__esModule",{value:!0}),e.appVersion=a,e.default=void 0
65
67
  var s=Ember.Helper.helper(a)
66
68
  e.default=s}),define("client-app/helpers/logster-url",["exports","client-app/lib/preload"],function(e,t){function n(e){var n=e[0]
67
69
  return"/"!==n[0]&&(n="/".concat(n)),t.default.get("rootPath")+n}Object.defineProperty(e,"__esModule",{value:!0}),e.logsterUrl=n,e.default=void 0
@@ -77,12 +79,12 @@ var n=["component","route"]
77
79
  function a(e){var a,s
78
80
  moment.updateLocale("en",{relativeTime:{future:"in %s",past:"%s ago",s:"secs",m:"a min",mm:"%d mins",h:"an hr",hh:"%d hrs",d:"a day",dd:"%d days",M:"a mth",MM:"%d mths",y:"a yr",yy:"%d yrs"}}),["","webkit","ms","moz","ms"].forEach(function(e){var t=e+(""===e?"hidden":"Hidden")
79
81
  void 0===document[t]||a||(a=t,s=e+"visibilitychange")}),(0,t.updateHiddenProperty)(a),document.addEventListener(s,function(){(0,t.resetTitleCount)()},!1),e.register("events:main",Ember.Object.extend(Ember.Evented).create(),{instantiate:!1}),n.forEach(function(t){return e.inject(t,"events","events:main")})
80
- var r=/mobile/i.test(navigator.userAgent)&&!/iPad/.test(navigator.userAgent)
81
- r&&Em.$("body").addClass("mobile"),e.register("site:main",{isMobile:r},{instantiate:!1}),e.inject("controller","site","site:main")}var s={initialize:a}
82
+ var i=/mobile/i.test(navigator.userAgent)&&!/iPad/.test(navigator.userAgent)
83
+ i&&Em.$("body").addClass("mobile"),e.register("site:main",{isMobile:i},{instantiate:!1}),e.inject("controller","site","site:main")}var s={initialize:a}
82
84
  e.default=s}),define("client-app/initializers/app-version",["exports","ember-cli-app-version/initializer-factory","client-app/config/environment"],function(e,t,n){var a,s
83
85
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0,n.default.APP&&(a=n.default.APP.name,s=n.default.APP.version)
84
- var r={name:"App Version",initialize:(0,t.default)(a,s)}
85
- e.default=r}),define("client-app/initializers/container-debug-adapter",["exports","ember-resolver/resolvers/classic/container-debug-adapter"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
86
+ var i={name:"App Version",initialize:(0,t.default)(a,s)}
87
+ e.default=i}),define("client-app/initializers/container-debug-adapter",["exports","ember-resolver/resolvers/classic/container-debug-adapter"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
86
88
  var n={name:"container-debug-adapter",initialize:function(){var e=arguments[1]||arguments[0]
87
89
  e.register("container-debug-adapter:main",t.default),e.inject("container-debug-adapter:main","namespace","application:main")}}
88
90
  e.default=n}),define("client-app/initializers/ember-data",["exports","ember-data/setup-container","ember-data"],function(e,t,n){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
@@ -104,22 +106,22 @@ function a(){var e=document.getElementById("preloaded-data").dataset
104
106
  t=Em.$.extend(JSON.parse(e.preloaded),{rootPath:e.rootPath}),n=!0}var s={get:function(e){return n||a(),Em.get(t,e)}}
105
107
  e.default=s}),define("client-app/lib/utilities",["exports","@babel/runtime/helpers/esm/typeof","client-app/lib/preload"],function(e,t,n){Object.defineProperty(e,"__esModule",{value:!0}),e.escapeHtml=o,e.ajax=l,e.preloadOrAjax=function(e,t){var a=n.default.get(e.replace(".json",""))
106
108
  return a?Em.RSVP.resolve(a):l(e,t)},e.updateHiddenProperty=function(e){a=e},e.isHidden=c,e.increaseTitleCount=function(e){if(!c())return
107
- s=s||document.title,r=r||0,r+=e,document.title="".concat(s," (").concat(r,")")},e.resetTitleCount=function(){r=0,document.title=s||document.title},e.formatTime=u,e.buildArrayString=d,e.buildHashString=function e(a,s){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[]
109
+ s=s||document.title,i=i||0,i+=e,document.title="".concat(s," (").concat(i,")")},e.resetTitleCount=function(){i=0,document.title=s||document.title},e.formatTime=u,e.buildArrayString=d,e.buildHashString=function e(a,s){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[]
108
110
  if(!a)return""
109
- var i=[]
111
+ var r=[]
110
112
  var l=[]
111
113
  var c=n.default.get("env_expandable_keys")||[]
112
- _.each(a,function(e,n){if(null===e)i.push("null")
114
+ _.each(a,function(e,n){if(null===e)r.push("null")
113
115
  else if("[object Array]"===Object.prototype.toString.call(e)){var a=""
114
- a=-1!==c.indexOf(n)&&!s&&-1===r.indexOf(n)&&e.length>3?"".concat(o(e[0]),', <a class="expand-list" data-key=').concat(n,">").concat(e.length-1," more</a>"):d(e),i.push("<tr><td>"+o(n)+"</td><td>"+a+"</td></tr>")}else if("object"===(0,t.default)(e))l.push(n)
116
+ a=-1!==c.indexOf(n)&&!s&&-1===i.indexOf(n)&&e.length>3?"".concat(o(e[0]),', <a class="expand-list" data-key=').concat(n,">").concat(e.length-1," more</a>"):d(e),r.push("<tr><td>"+o(n)+"</td><td>"+a+"</td></tr>")}else if("object"===(0,t.default)(e))l.push(n)
115
117
  else if("time"===n&&"number"==typeof e){var p=moment(e).format(),f=u(e)
116
- i.push('<tr title="'.concat(p,'"><td>').concat(n,"</td><td>").concat(f,"</td></tr>"))}else i.push("<tr><td>".concat(o(n),"</td><td>").concat(o(e),"</td></tr>"))})
118
+ r.push('<tr title="'.concat(p,'"><td>').concat(n,"</td><td>").concat(f,"</td></tr>"))}else r.push("<tr><td>".concat(o(n),"</td><td>").concat(o(e),"</td></tr>"))})
117
119
  _.size(l)>0&&_.each(l,function(t){var n=a[t]
118
- i.push("<tr><td></td><td><table>"),i.push("<td>"+o(t)+"</td><td>"+e(n,!0)+"</td>"),i.push("</table></td></tr>")})
120
+ r.push("<tr><td></td><td><table>"),r.push("<td>"+o(t)+"</td><td>"+e(n,!0)+"</td>"),r.push("</table></td></tr>")})
119
121
  var p=s?"":"env-table"
120
- return"<table class='"+p+"'>"+i.join("\n")+"</table>"}
121
- var a,s,r,i={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;"}
122
- function o(e){return String(e).replace(/[&<>"'\/]/g,function(e){return i[e]})}function l(e,t){return(t=t||{}).headers=t.headers||{},t.headers["X-SILENCE-LOGGER"]=!0,Em.$.ajax(n.default.get("rootPath")+e,t)}function c(){return void 0!==a?document[a]:!document.hasFocus}function u(e){var t=moment(e),n=moment()
122
+ return"<table class='"+p+"'>"+r.join("\n")+"</table>"}
123
+ var a,s,i,r={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;"}
124
+ function o(e){return String(e).replace(/[&<>"'\/]/g,function(e){return r[e]})}function l(e,t){return(t=t||{}).headers=t.headers||{},t.headers["X-SILENCE-LOGGER"]=!0,Em.$.ajax(n.default.get("rootPath")+e,t)}function c(){return void 0!==a?document[a]:!document.hasFocus}function u(e){var t=moment(e),n=moment()
123
125
  return t.diff(n.startOf("day"))>0?t.format("h:mm a"):t.diff(n.startOf("week"))>0?t.format("dd h:mm a"):t.diff(n.startOf("year"))>0?t.format("D MMM h:mm a"):t.format("D MMM YY")}function d(e){var t=[]
124
126
  return e.forEach(function(e){null===e?t.push("null"):"[object Array]"===Object.prototype.toString.call(e)?t.push(d(e)):t.push(o(e.toString()))}),"["+t.join(", ")+"]"}}),define("client-app/models/message-collection",["exports","client-app/lib/utilities","client-app/models/message"],function(e,t,n){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
125
127
  var a=Em.Object.extend({messages:Em.A(),currentMessage:null,total:0,solve:function(e){var t=this
@@ -128,8 +130,8 @@ e.destroy(),e.set("selected",!1),this.set("total",this.get("total")-1),this.get(
128
130
  e=e||{}
129
131
  var a={filter:this.get("filter").join("_")},s=this.get("search")
130
132
  _.isEmpty(s)||(a.search=s,this.get("regexSearch")&&(a.regex_search="true"))
131
- return e.before&&(a.before=e.before),e.after&&(a.after=e.after),(0,t.ajax)("/messages.json",{data:a}).then(function(a){if(0==Ember.compare(a.filter,n.get("filter"))&&0==Ember.compare(a.search,n.get("search"))){if(a.messages.length>0){var s=n.toMessages(a.messages),r=n.get("messages")
132
- e.before?r.unshiftObjects(s):(s.forEach(function(e){r.forEach(function(t){t.key==e.key&&(r.removeObject(t),n.get("currentMessage")===t&&(n.set("currentMessage",e),e.set("selected",t.get("selected"))))})}),r.addObjects(s),s.length>0&&(0,t.increaseTitleCount)(s.length))}return n.set("total",a.total),a}})},reload:function(){var e=this
133
+ return e.before&&(a.before=e.before),e.after&&(a.after=e.after),this.set("loading",!0),(0,t.ajax)("/messages.json",{data:a}).then(function(a){if(0==Ember.compare(a.filter,n.get("filter"))&&0==Ember.compare(a.search,n.get("search"))){if(a.messages.length>0){var s=n.toMessages(a.messages),i=n.get("messages")
134
+ e.before?i.unshiftObjects(s):(s.forEach(function(e){i.forEach(function(t){t.key==e.key&&(i.removeObject(t),n.get("currentMessage")===t&&(n.set("currentMessage",e),e.set("selected",t.get("selected"))))})}),i.addObjects(s),s.length>0&&(0,t.increaseTitleCount)(s.length))}return n.set("total",a.total),a}}).always(function(){return n.set("loading",!1)})},reload:function(){var e=this
133
135
  return this.set("total",0),this.get("messages").clear(),this.load().then(function(t){return e.updateCanLoadMore(t)})},updateCanLoadMore:function(e){e&&(e.messages.length<50?this.set("canLoadMore",!1):this.set("canLoadMore",!0))},loadMore:function(){var e=this.get("messages")
134
136
  if(0!==e.length){var t=e[e.length-1].get("key")
135
137
  this.load({after:t})}else this.load({})},hideCountInLoadMore:Ember.computed("search","filter",function(){var e=this.get("search"),t=this.get("filter")
@@ -161,13 +163,13 @@ var a=n
161
163
  e.default=a}),define("client-app/routes/index",["exports","client-app/models/message-collection","client-app/lib/utilities"],function(e,t,n){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
162
164
  var a=Ember.Route.extend({model:function(){return t.default.create()},setupController:function(e,t){this._super(e,t),t.setProperties(e.getProperties("filter","search")),t.reload(),e.set("initialized",!0)
163
165
  var a=0,s=1
164
- this.refreshInterval=setInterval(function(){a+=1
165
- var e=(0,n.isHidden)(),r=!e
166
- e&&a%s==0&&(r=!0,s<20&&s++),r&&(t.loadMore(),e||(s=1))},3e3),this.events.on("panelResized",function(t){e.resizePanels(t)})},deactivate:function(){clearInterval(this.refreshInterval)}})
166
+ this.refreshInterval=setInterval(function(){if(!t.loading){a+=1
167
+ var e=(0,n.isHidden)(),i=!e
168
+ e&&a%s==0&&(i=!0,s<20&&s++),i&&(t.loadMore(),e||(s=1))}},3e3),this.events.on("panelResized",function(t){e.resizePanels(t)})},deactivate:function(){clearInterval(this.refreshInterval)}})
167
169
  e.default=a}),define("client-app/routes/settings",["exports","client-app/lib/utilities","client-app/models/pattern-item"],function(e,t,n){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
168
170
  var a=Ember.Route.extend({model:function(){return(0,t.ajax)("/settings.json")},setupController:function(e,t){this._super.apply(this,arguments)
169
- var a=t.suppression,s=a.filter(function(e){return e.hard}).map(function(e){return n.default.create(e)}),r=a.reject(function(e){return e.hard}).map(function(e){return n.default.create(e)}),i=s.length>0
170
- e.setProperties({showCodedSuppression:i,codedSuppression:s,customSuppression:r})}})
171
+ var a=t.suppression,s=a.filter(function(e){return e.hard}).map(function(e){return n.default.create(e)}),i=a.reject(function(e){return e.hard}).map(function(e){return n.default.create(e)}),r=s.length>0
172
+ e.setProperties({showCodedSuppression:r,codedSuppression:s,customSuppression:i})}})
171
173
  e.default=a}),define("client-app/routes/show",["exports","client-app/models/message","client-app/lib/utilities"],function(e,t,n){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
172
174
  var a=Ember.Route.extend({model:function(e){return(0,n.preloadOrAjax)("/show/"+e.id+".json")},setupController:function(e,n){this._super.apply(this,arguments),e.set("model",t.default.create(n))}})
173
175
  e.default=a}),define("client-app/services/ajax",["exports","ember-ajax/services/ajax"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}})}),define("client-app/templates/application",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
@@ -177,7 +179,7 @@ var t=Ember.HTMLBars.template({id:"iO5WYaED",block:'{"symbols":["&default"],"sta
177
179
  e.default=t}),define("client-app/templates/components/env-tab",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
178
180
  var t=Ember.HTMLBars.template({id:"X1VwEK8H",block:'{"symbols":[],"statements":[[4,"if",[[23,["isEnvArray"]]],null,{"statements":[[0," "],[7,"div"],[11,"class","nav-controls"],[9],[0,"\\n "],[7,"button"],[12,"disabled",[21,"disableBackButtons"]],[11,"class","btn nav-btn no-text"],[9],[7,"i"],[11,"class","fa fa-fast-backward"],[9],[10],[3,"action",[[22,0,[]],"bigJump","back"]],[10],[0,"\\n "],[7,"button"],[12,"disabled",[21,"disableBackButtons"]],[11,"class","btn nav-btn no-text"],[9],[7,"i"],[11,"class","fa fa-backward"],[9],[10],[3,"action",[[22,0,[]],"takeStep","back"]],[10],[0,"\\n "],[7,"span"],[11,"class","env-number"],[9],[1,[21,"current"],false],[0,"/"],[1,[23,["message","env","length"]],false],[10],[0,"\\n "],[7,"button"],[12,"disabled",[21,"disableForwardButtons"]],[11,"class","btn nav-btn no-text"],[9],[7,"i"],[11,"class","fa fa-forward"],[9],[10],[3,"action",[[22,0,[]],"takeStep","front"]],[10],[0,"\\n "],[7,"button"],[12,"disabled",[21,"disableForwardButtons"]],[11,"class","btn nav-btn no-text"],[9],[7,"i"],[11,"class","fa fa-fast-forward"],[9],[10],[3,"action",[[22,0,[]],"bigJump","front"]],[10],[0,"\\n "],[10],[0,"\\n"]],"parameters":[]},null],[1,[21,"html"],true],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"client-app/templates/components/env-tab.hbs"}})
179
181
  e.default=t}),define("client-app/templates/components/message-info",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
180
- var t=Ember.HTMLBars.template({id:"Jwt+/aHp",block:'{"symbols":["btn"],"statements":[[7,"div"],[11,"class","message-info"],[9],[0,"\\n"],[4,"tabbed-section",null,null,{"statements":[[4,"tab-contents",null,[["name","hint","currentMessage"],["info","show info",[23,["currentMessage"]]]],{"statements":[[4,"if",[[23,["showTitle"]]],null,{"statements":[[0," "],[7,"h3"],[9],[0,"Message\\n"],[4,"if",[[23,["currentMessage","showCount"]]],null,{"statements":[[0," ("],[1,[23,["currentMessage","count"]],false],[0," copies reported)\\n"]],"parameters":[]},null],[0," "],[10],[0,"\\n"]],"parameters":[]},null],[0," "],[7,"pre"],[9],[1,[23,["currentMessage","message"]],false],[10],[0,""]],"parameters":[]},null],[4,"tab-contents",null,[["name","defaultTab","hint","currentMessage"],["backtrace","true","show backtrace",[23,["currentMessage"]]]],{"statements":[[4,"if",[[23,["showTitle"]]],null,{"statements":[[0," "],[7,"h3"],[9],[0,"Backtrace"],[10],[0,"\\n"]],"parameters":[]},null],[0," "],[7,"pre"],[9],[1,[23,["currentMessage","backtrace"]],false],[10],[0,""]],"parameters":[]},null],[4,"if",[[23,["currentMessage","env"]]],null,{"statements":[[4,"tab-contents",null,[["className","name","hint","currentMessage"],["env","env","show environment",[23,["currentMessage"]]]],{"statements":[[4,"if",[[23,["showTitle"]]],null,{"statements":[[0," "],[7,"h3"],[9],[0,"Env"],[10],[0,"\\n"]],"parameters":[]},null],[0," "],[1,[27,"env-tab",null,[["message"],[[23,["currentMessage"]]]]],false],[0,"\\n"]],"parameters":[]},null]],"parameters":[]},null]],"parameters":[]},null],[0,"\\n"],[4,"if",[[23,["currentMessage"]]],null,{"statements":[[0," "],[7,"div"],[11,"class","message-actions"],[9],[0,"\\n"],[4,"actions-menu",null,[["actionsInMenu","share"],[[23,["actionsInMenu"]],[27,"action",[[22,0,[]],"share"],null]]],{"statements":[[4,"each",[[23,["buttons"]]],null,{"statements":[[0," "],[7,"button"],[12,"class",[28,[[22,1,["klass"]]," btn ",[27,"if",[[22,1,["danger"]],"danger",""],null]]]],[9],[0,"\\n "],[7,"i"],[12,"class",[28,["fa fa-",[22,1,["icon"]]]]],[9],[10],[0,"\\n "],[7,"span"],[9],[1,[22,1,["label"]],false],[10],[0,"\\n "],[3,"action",[[22,0,[]],[22,1,["action"]]]],[10],[0,"\\n"]],"parameters":[1]},null]],"parameters":[]},null],[0," "],[10],[0,"\\n"]],"parameters":[]},null],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"client-app/templates/components/message-info.hbs"}})
182
+ var t=Ember.HTMLBars.template({id:"gPjmElUI",block:'{"symbols":["btn"],"statements":[[7,"div"],[11,"class","message-info"],[9],[0,"\\n"],[4,"tabbed-section",null,[["onTabChange"],[[27,"action",[[22,0,[]],"tabChanged"],null]]],{"statements":[[4,"tab-contents",null,[["name","hint","currentMessage"],["info","show info",[23,["currentMessage"]]]],{"statements":[[4,"if",[[23,["showTitle"]]],null,{"statements":[[0," "],[7,"h3"],[9],[0,"Message\\n"],[4,"if",[[23,["currentMessage","showCount"]]],null,{"statements":[[0," ("],[1,[23,["currentMessage","count"]],false],[0," copies reported)\\n"]],"parameters":[]},null],[0," "],[10],[0,"\\n"]],"parameters":[]},null],[0," "],[7,"pre"],[9],[1,[23,["currentMessage","message"]],false],[10],[0,""]],"parameters":[]},null],[4,"tab-contents",null,[["name","defaultTab","hint","currentMessage"],["backtrace","true","show backtrace",[23,["currentMessage"]]]],{"statements":[[4,"if",[[23,["showTitle"]]],null,{"statements":[[0," "],[7,"h3"],[9],[0,"Backtrace"],[10],[0,"\\n"]],"parameters":[]},null],[0," "],[7,"pre"],[9],[1,[23,["currentMessage","backtrace"]],false],[10],[0,""]],"parameters":[]},null],[4,"tab-contents",null,[["className","name","hint","currentMessage"],["env","env","show environment",[23,["currentMessage"]]]],{"statements":[[4,"if",[[23,["currentMessage","env"]]],null,{"statements":[[4,"if",[[23,["showTitle"]]],null,{"statements":[[0," "],[7,"h3"],[9],[0,"Env"],[10],[0,"\\n"]],"parameters":[]},null],[0," "],[1,[27,"env-tab",null,[["message"],[[23,["currentMessage"]]]]],false],[0,"\\n"]],"parameters":[]},{"statements":[[4,"if",[[23,["loadingEnv"]]],null,{"statements":[[0," Loading env...\\n"]],"parameters":[]},{"statements":[[0," No env for this message.\\n "]],"parameters":[]}]],"parameters":[]}]],"parameters":[]},null]],"parameters":[]},null],[0,"\\n"],[4,"if",[[23,["currentMessage"]]],null,{"statements":[[0," "],[7,"div"],[11,"class","message-actions"],[9],[0,"\\n"],[4,"actions-menu",null,[["actionsInMenu","share"],[[23,["actionsInMenu"]],[27,"action",[[22,0,[]],"share"],null]]],{"statements":[[4,"each",[[23,["buttons"]]],null,{"statements":[[0," "],[7,"button"],[12,"class",[28,[[22,1,["klass"]]," btn ",[27,"if",[[22,1,["danger"]],"danger",""],null]]]],[9],[0,"\\n "],[7,"i"],[12,"class",[28,["fa fa-",[22,1,["icon"]]]]],[9],[10],[0,"\\n "],[7,"span"],[9],[1,[22,1,["label"]],false],[10],[0,"\\n "],[3,"action",[[22,0,[]],[22,1,["action"]]]],[10],[0,"\\n"]],"parameters":[1]},null]],"parameters":[]},null],[0," "],[10],[0,"\\n"]],"parameters":[]},null],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"client-app/templates/components/message-info.hbs"}})
181
183
  e.default=t}),define("client-app/templates/components/message-row",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
182
184
  var t=Ember.HTMLBars.template({id:"pF0hQ9a+",block:'{"symbols":[],"statements":[[7,"div"],[11,"class","count"],[9],[0,"\\n"],[4,"if",[[23,["model","showCount"]]],null,{"statements":[[0," "],[1,[23,["model","count"]],false],[0,"\\n"]],"parameters":[]},null],[10],[0,"\\n"],[7,"div"],[11,"class","severity"],[9],[1,[23,["model","glyph"]],true],[10],[0,"\\n"],[7,"div"],[11,"class","message-body"],[9],[0,"\\n "],[1,[23,["model","displayMessage"]],false],[0,"\\n"],[10],[0,"\\n"],[7,"div"],[11,"class","protected"],[9],[0,"\\n"],[4,"if",[[23,["model","protected"]]],null,{"statements":[[0," "],[7,"i"],[11,"title","message is protected, clearing will not remove it"],[11,"class","fa fa-lock"],[9],[10],[0,"\\n"]],"parameters":[]},null],[10],[0,"\\n"],[7,"div"],[11,"class","time"],[9],[1,[27,"time-formatter",null,[["timestamp"],[[23,["model","timestamp"]]]]],false],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"client-app/templates/components/message-row.hbs"}})
183
185
  e.default=t}),define("client-app/templates/components/panel-resizer",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
@@ -189,10 +191,10 @@ var t=Ember.HTMLBars.template({id:"zCP0V00P",block:'{"symbols":["tab","&default"
189
191
  e.default=t}),define("client-app/templates/components/time-formatter",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
190
192
  var t=Ember.HTMLBars.template({id:"sp53cTcH",block:'{"symbols":[],"statements":[[1,[21,"time"],false],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"client-app/templates/components/time-formatter.hbs"}})
191
193
  e.default=t}),define("client-app/templates/index",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
192
- var t=Ember.HTMLBars.template({id:"i9LWBRFJ",block:'{"symbols":["message"],"statements":[[7,"div"],[11,"id","top-panel"],[9],[0,"\\n "],[7,"div"],[11,"id","log-table"],[9],[0,"\\n"],[4,"if",[[23,["model","moreBefore"]]],null,{"statements":[[0," "],[7,"div"],[11,"class","show-more"],[9],[0,"\\n"],[4,"if",[[23,["model","hideCountInLoadMore"]]],null,{"statements":[[0," Load more\\n"]],"parameters":[]},{"statements":[[0," Select to see "],[1,[23,["model","totalBefore"]],false],[0," more\\n"]],"parameters":[]}],[0," "],[3,"action",[[22,0,[]],"showMoreBefore"]],[10],[0,"\\n"]],"parameters":[]},null],[4,"each",[[23,["model","messages"]]],null,{"statements":[[0," "],[1,[27,"message-row",null,[["model","selectedMessage"],[[22,1,[]],[27,"action",[[22,0,[]],"selectMessage"],null]]]],false],[0,"\\n"]],"parameters":[1]},null],[0," "],[10],[0,"\\n"],[10],[0,"\\n"],[7,"div"],[11,"id","bottom-panel"],[9],[0,"\\n "],[1,[27,"message-info",null,[["currentMessage","removeMessage","solveMessage","actionsInMenu"],[[23,["currentMessage"]],[27,"action",[[22,0,[]],"removeMessage"],null],[27,"action",[[22,0,[]],"solveMessage"],null],[23,["actionsInMenu"]]]]],false],[0,"\\n\\n "],[7,"div"],[11,"class","action-panel"],[9],[0,"\\n "],[7,"div"],[11,"class","severity-filters"],[9],[0,"\\n "],[7,"div"],[11,"class","more-wrapping"],[9],[0,"\\n "],[7,"label"],[11,"class","debug"],[9],[0,"\\n "],[1,[27,"input",null,[["type","checked"],["checkbox",[23,["showDebug"]]]]],false],[0,"\\n "],[7,"span"],[9],[0,"Debug"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"label"],[11,"class","info"],[9],[0,"\\n "],[1,[27,"input",null,[["type","checked"],["checkbox",[23,["showInfo"]]]]],false],[0,"\\n "],[7,"span"],[9],[0,"Info"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"label"],[11,"class","warn"],[9],[0,"\\n "],[1,[27,"input",null,[["type","checked"],["checkbox",[23,["showWarn"]]]]],false],[0,"\\n "],[7,"i"],[11,"class","fa fa-exclamation-circle warning"],[9],[10],[0,"\\n "],[7,"span"],[9],[0,"Warning"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"label"],[11,"class","error"],[9],[0,"\\n "],[1,[27,"input",null,[["type","checked"],["checkbox",[23,["showErr"]]]]],false],[0,"\\n "],[7,"i"],[11,"class","fa fa-times-circle error"],[9],[10],[0,"\\n "],[7,"span"],[9],[0,"Error"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"label"],[11,"class","fatal"],[9],[0,"\\n "],[1,[27,"input",null,[["type","checked"],["checkbox",[23,["showFatal"]]]]],false],[0,"\\n "],[7,"i"],[11,"class","fa fa-times-circle fatal"],[9],[10],[0,"\\n "],[7,"span"],[9],[0,"Fatal"],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[7,"div"],[11,"class","search-clear-all"],[9],[0,"\\n "],[1,[27,"input",null,[["type","class","placeholder","value"],["textfield","search","Search",[23,["search"]]]]],false],[0,"\\n "],[7,"div"],[11,"class","footer-btns"],[9],[0,"\\n"],[4,"if",[[23,["showSettings"]]],null,{"statements":[[4,"link-to",["settings"],[["class"],["settings btn no-text"]],{"statements":[[0," "],[7,"i"],[11,"class","fa fa-cog"],[9],[10],[0,"\\n"]],"parameters":[]},null]],"parameters":[]},null],[0," "],[7,"button"],[11,"class","clear btn danger"],[9],[7,"i"],[11,"class","fa fa-trash-o"],[9],[10],[7,"span"],[9],[0,"Clear logs"],[10],[3,"action",[[22,0,[]],"clear"]],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n"],[10],[0,"\\n"],[1,[21,"panel-resizer"],false],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"client-app/templates/index.hbs"}})
194
+ var t=Ember.HTMLBars.template({id:"2nOvOGVv",block:'{"symbols":["message"],"statements":[[7,"div"],[11,"id","top-panel"],[9],[0,"\\n "],[7,"div"],[11,"id","log-table"],[9],[0,"\\n"],[4,"if",[[23,["model","moreBefore"]]],null,{"statements":[[0," "],[7,"div"],[11,"class","show-more"],[9],[0,"\\n"],[4,"if",[[23,["model","hideCountInLoadMore"]]],null,{"statements":[[0," Load more\\n"]],"parameters":[]},{"statements":[[0," Select to see "],[1,[23,["model","totalBefore"]],false],[0," more\\n"]],"parameters":[]}],[0," "],[3,"action",[[22,0,[]],"showMoreBefore"]],[10],[0,"\\n"]],"parameters":[]},null],[4,"each",[[23,["model","messages"]]],null,{"statements":[[0," "],[1,[27,"message-row",null,[["model","selectedMessage"],[[22,1,[]],[27,"action",[[22,0,[]],"selectMessage"],null]]]],false],[0,"\\n"]],"parameters":[1]},null],[0," "],[10],[0,"\\n"],[10],[0,"\\n"],[7,"div"],[11,"id","bottom-panel"],[9],[0,"\\n "],[1,[27,"message-info",null,[["currentMessage","loadingEnv","removeMessage","solveMessage","onTabChange","actionsInMenu"],[[23,["currentMessage"]],[23,["loadingEnv"]],[27,"action",[[22,0,[]],"removeMessage"],null],[27,"action",[[22,0,[]],"solveMessage"],null],[27,"action",[[22,0,[]],"tabChanged"],null],[23,["actionsInMenu"]]]]],false],[0,"\\n\\n "],[7,"div"],[11,"class","action-panel"],[9],[0,"\\n "],[7,"div"],[11,"class","severity-filters"],[9],[0,"\\n "],[7,"div"],[11,"class","more-wrapping"],[9],[0,"\\n "],[7,"label"],[11,"class","debug"],[9],[0,"\\n "],[1,[27,"input",null,[["type","checked"],["checkbox",[23,["showDebug"]]]]],false],[0,"\\n "],[7,"span"],[9],[0,"Debug"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"label"],[11,"class","info"],[9],[0,"\\n "],[1,[27,"input",null,[["type","checked"],["checkbox",[23,["showInfo"]]]]],false],[0,"\\n "],[7,"span"],[9],[0,"Info"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"label"],[11,"class","warn"],[9],[0,"\\n "],[1,[27,"input",null,[["type","checked"],["checkbox",[23,["showWarn"]]]]],false],[0,"\\n "],[7,"i"],[11,"class","fa fa-exclamation-circle warning"],[9],[10],[0,"\\n "],[7,"span"],[9],[0,"Warning"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"label"],[11,"class","error"],[9],[0,"\\n "],[1,[27,"input",null,[["type","checked"],["checkbox",[23,["showErr"]]]]],false],[0,"\\n "],[7,"i"],[11,"class","fa fa-times-circle error"],[9],[10],[0,"\\n "],[7,"span"],[9],[0,"Error"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"label"],[11,"class","fatal"],[9],[0,"\\n "],[1,[27,"input",null,[["type","checked"],["checkbox",[23,["showFatal"]]]]],false],[0,"\\n "],[7,"i"],[11,"class","fa fa-times-circle fatal"],[9],[10],[0,"\\n "],[7,"span"],[9],[0,"Fatal"],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[7,"div"],[11,"class","search-clear-all"],[9],[0,"\\n "],[1,[27,"input",null,[["type","class","placeholder","value"],["textfield","search","Search",[23,["search"]]]]],false],[0,"\\n "],[7,"div"],[11,"class","footer-btns"],[9],[0,"\\n"],[4,"if",[[23,["showSettings"]]],null,{"statements":[[4,"link-to",["settings"],[["class"],["settings btn no-text"]],{"statements":[[0," "],[7,"i"],[11,"class","fa fa-cog"],[9],[10],[0,"\\n"]],"parameters":[]},null]],"parameters":[]},null],[0," "],[7,"button"],[11,"class","clear btn danger"],[9],[7,"i"],[11,"class","fa fa-trash-o"],[9],[10],[7,"span"],[9],[0,"Clear logs"],[10],[3,"action",[[22,0,[]],"clear"]],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n"],[10],[0,"\\n"],[1,[21,"panel-resizer"],false],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"client-app/templates/index.hbs"}})
193
195
  e.default=t}),define("client-app/templates/settings",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
194
196
  var t=Ember.HTMLBars.template({id:"ZVQ4fCm0",block:'{"symbols":[],"statements":[[7,"div"],[11,"class","settings-page"],[9],[0,"\\n "],[4,"link-to",["index"],null,{"statements":[[0,"Home"]],"parameters":[]},null],[0,"\\n "],[7,"div"],[11,"class","settings-header"],[9],[0,"\\n "],[7,"h1"],[11,"class","header-title"],[9],[0,"Settings"],[10],[0,"\\n "],[7,"img"],[11,"class","header-logo"],[12,"src",[27,"logster-url",["images/icon_144x144.png"],null]],[9],[10],[0,"\\n "],[10],[0,"\\n\\n "],[7,"div"],[11,"class","settings-section suppression-patterns"],[9],[0,"\\n "],[7,"h2"],[11,"class","section-title"],[9],[0,"Suppression Patterns"],[10],[0,"\\n "],[7,"div"],[9],[0,"New messages that match these Regular Expression patterns will be suppressed."],[10],[0,"\\n\\n"],[4,"if",[[23,["showCodedSuppression"]]],null,{"statements":[[0," "],[7,"h3"],[11,"class","subsection-title"],[9],[0,"Hard-coded patterns:"],[10],[0,"\\n "],[7,"div"],[11,"class","tip"],[9],[0,"These patterns can\'t be removed via the UI because they are commited to the source code of your app."],[10],[0,"\\n "],[1,[27,"patterns-list",null,[["patterns","mutable"],[[23,["codedSuppression"]],false]]],false],[0,"\\n"]],"parameters":[]},null],[0,"\\n "],[7,"h3"],[11,"class","subsection-title"],[9],[0,"Custom patterns:"],[10],[0,"\\n "],[1,[27,"patterns-list",null,[["patterns","key","applyRetroactivelyCheckbox","mutable"],[[23,["customSuppression"]],"suppression",true,true]]],false],[0,"\\n "],[10],[0,"\\n"],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"client-app/templates/settings.hbs"}})
195
197
  e.default=t}),define("client-app/templates/show",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
196
198
  var t=Ember.HTMLBars.template({id:"V916vpg9",block:'{"symbols":[],"statements":[[4,"link-to",["index"],null,{"statements":[[0,"Recent"]],"parameters":[]},null],[0,"\\n"],[7,"div"],[11,"id","bottom-panel"],[11,"class","full"],[9],[0,"\\n "],[1,[27,"message-info",null,[["currentMessage","showTitle","actionsInMenu"],[[23,["model"]],"true",false]]],false],[0,"\\n"],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"client-app/templates/show.hbs"}})
197
199
  e.default=t}),define("client-app/config/environment",[],function(){try{var e="client-app/config/environment",t=document.querySelector('meta[name="'+e+'"]').getAttribute("content"),n={default:JSON.parse(decodeURIComponent(t))}
198
- return Object.defineProperty(n,"__esModule",{value:!0}),n}catch(a){throw new Error('Could not read config from meta tag with name "'+e+'".')}}),runningTests||require("client-app/app").default.create({name:"client-app",version:"0.0.0+ce647650"})
200
+ return Object.defineProperty(n,"__esModule",{value:!0}),n}catch(a){throw new Error('Could not read config from meta tag with name "'+e+'".')}}),runningTests||require("client-app/app").default.create({name:"client-app",version:"0.0.0+9798c0bc"})
@@ -46,6 +46,12 @@ export default Component.extend({
46
46
  }),
47
47
 
48
48
  actions: {
49
+ tabChanged(newTab) {
50
+ if (this.onTabChange) {
51
+ this.onTabChange(newTab);
52
+ }
53
+ },
54
+
49
55
  protect() {
50
56
  this.get("currentMessage").protect();
51
57
  },
@@ -14,6 +14,7 @@ export default Component.extend({
14
14
  }
15
15
  this.set("selected", view);
16
16
  view.set("active", true);
17
+ this.onTabChange(view.name);
17
18
  },
18
19
 
19
20
  addTab(tab) {
@@ -2,6 +2,7 @@ import Controller from "@ember/controller";
2
2
  import { ajax } from "client-app/lib/utilities";
3
3
  import { observer, computed } from "@ember/object";
4
4
  import Preload from "client-app/lib/preload";
5
+ import { debounce } from "@ember/runloop";
5
6
 
6
7
  export default Controller.extend({
7
8
  showDebug: true,
@@ -11,6 +12,7 @@ export default Controller.extend({
11
12
  showFatal: true,
12
13
  search: "",
13
14
  currentMessage: Em.computed.alias("model.currentMessage"),
15
+ currentTab: null,
14
16
 
15
17
  showSettings: computed(function() {
16
18
  return Preload.get("patterns_enabled");
@@ -25,6 +27,16 @@ export default Controller.extend({
25
27
  return this.site.isMobile;
26
28
  }),
27
29
 
30
+ fetchEnv() {
31
+ const message = this.get("currentMessage");
32
+ if (message) {
33
+ this.set("loadingEnv", true);
34
+ return ajax(`/fetch-env/${message.key}.json`)
35
+ .then(env => message.set("env", env))
36
+ .always(() => this.set("loadingEnv", false));
37
+ }
38
+ },
39
+
28
40
  actions: {
29
41
  expandMessage(message) {
30
42
  message.expand();
@@ -37,7 +49,23 @@ export default Controller.extend({
37
49
  }
38
50
 
39
51
  message.set("selected", true);
40
- this.set("currentMessage", message);
52
+ this.setProperties({
53
+ currentMessage: message,
54
+ loadingEnv: false
55
+ });
56
+ if (!message.env && this.currentTab === "env") {
57
+ this.fetchEnv();
58
+ }
59
+ },
60
+
61
+ tabChanged(newTab) {
62
+ this.setProperties({
63
+ currentTab: newTab,
64
+ loadingEnv: false
65
+ });
66
+ if (newTab === "env" && !this.get("currentMessage.env")) {
67
+ this.fetchEnv();
68
+ }
41
69
  },
42
70
 
43
71
  showMoreBefore() {
@@ -109,13 +137,21 @@ export default Controller.extend({
109
137
  }
110
138
  }),
111
139
 
112
- searchChanged: observer("search", function() {
113
- const search = this.get("search");
140
+ doSearch(term) {
114
141
  const model = this.get("model");
115
- model.set("search", search);
142
+ model.set("search", term);
116
143
 
117
144
  if (this.get("initialized")) {
118
145
  model.reload().then(() => this.updateSelectedMessage());
119
146
  }
147
+ },
148
+
149
+ searchChanged: observer("search", function() {
150
+ const term = this.search;
151
+ const termSize = term && term.length;
152
+ if (termSize && termSize === 1) {
153
+ return;
154
+ }
155
+ debounce(this, this.doSearch, term, 250);
120
156
  })
121
157
  });
@@ -63,45 +63,48 @@ export default Em.Object.extend({
63
63
  data.after = opts.after;
64
64
  }
65
65
 
66
+ this.set("loading", true);
66
67
  return ajax("/messages.json", {
67
68
  data: data
68
- }).then(data => {
69
- // guard against race: ensure the results we're trying to apply
70
- // match the current search terms
71
- if (compare(data.filter, this.get("filter")) != 0) {
72
- return;
73
- }
74
- if (compare(data.search, this.get("search")) != 0) {
75
- return;
76
- }
69
+ })
70
+ .then(data => {
71
+ // guard against race: ensure the results we're trying to apply
72
+ // match the current search terms
73
+ if (compare(data.filter, this.get("filter")) != 0) {
74
+ return;
75
+ }
76
+ if (compare(data.search, this.get("search")) != 0) {
77
+ return;
78
+ }
77
79
 
78
- if (data.messages.length > 0) {
79
- const newRows = this.toMessages(data.messages);
80
- const messages = this.get("messages");
81
- if (opts.before) {
82
- messages.unshiftObjects(newRows);
83
- } else {
84
- newRows.forEach(nmsg => {
85
- messages.forEach(emsg => {
86
- if (emsg.key == nmsg.key) {
87
- messages.removeObject(emsg);
88
- if (this.get("currentMessage") === emsg) {
89
- // TODO would updateFromJson() work here?
90
- this.set("currentMessage", nmsg);
91
- nmsg.set("selected", emsg.get("selected"));
80
+ if (data.messages.length > 0) {
81
+ const newRows = this.toMessages(data.messages);
82
+ const messages = this.get("messages");
83
+ if (opts.before) {
84
+ messages.unshiftObjects(newRows);
85
+ } else {
86
+ newRows.forEach(nmsg => {
87
+ messages.forEach(emsg => {
88
+ if (emsg.key == nmsg.key) {
89
+ messages.removeObject(emsg);
90
+ if (this.get("currentMessage") === emsg) {
91
+ // TODO would updateFromJson() work here?
92
+ this.set("currentMessage", nmsg);
93
+ nmsg.set("selected", emsg.get("selected"));
94
+ }
92
95
  }
93
- }
96
+ });
94
97
  });
95
- });
96
- messages.addObjects(newRows);
97
- if (newRows.length > 0) {
98
- increaseTitleCount(newRows.length);
98
+ messages.addObjects(newRows);
99
+ if (newRows.length > 0) {
100
+ increaseTitleCount(newRows.length);
101
+ }
99
102
  }
100
103
  }
101
- }
102
- this.set("total", data.total);
103
- return data;
104
- });
104
+ this.set("total", data.total);
105
+ return data;
106
+ })
107
+ .always(() => this.set("loading", false));
105
108
  },
106
109
 
107
110
  reload() {
@@ -18,6 +18,9 @@ export default Route.extend({
18
18
  let backoff = 1;
19
19
 
20
20
  this.refreshInterval = setInterval(() => {
21
+ if (model.loading) {
22
+ return;
23
+ }
21
24
  times += 1;
22
25
  const hidden = isHidden();
23
26
  let load = !hidden;
@@ -1,5 +1,5 @@
1
1
  <div class="message-info">
2
- {{#tabbed-section}}
2
+ {{#tabbed-section onTabChange=(action "tabChanged")}}
3
3
  {{#tab-contents name="info" hint="show info" currentMessage=currentMessage}}
4
4
  {{#if showTitle}}
5
5
  <h3>Message
@@ -16,14 +16,18 @@
16
16
  {{/if}}
17
17
  <pre>{{currentMessage.backtrace}}</pre>
18
18
  {{/tab-contents}}
19
- {{#if currentMessage.env}}
20
- {{#tab-contents className="env" name="env" hint="show environment" currentMessage=currentMessage}}
19
+ {{#tab-contents className="env" name="env" hint="show environment" currentMessage=currentMessage }}
20
+ {{#if currentMessage.env}}
21
21
  {{#if showTitle}}
22
22
  <h3>Env</h3>
23
23
  {{/if}}
24
24
  {{env-tab message=currentMessage}}
25
- {{/tab-contents}}
26
- {{/if}}
25
+ {{else if loadingEnv}}
26
+ Loading env...
27
+ {{else}}
28
+ No env for this message.
29
+ {{/if}}
30
+ {{/tab-contents}}
27
31
  {{/tabbed-section}}
28
32
 
29
33
  {{#if currentMessage}}
@@ -17,8 +17,10 @@
17
17
  <div id="bottom-panel">
18
18
  {{message-info
19
19
  currentMessage=currentMessage
20
+ loadingEnv=loadingEnv
20
21
  removeMessage=(action "removeMessage")
21
22
  solveMessage=(action "solveMessage")
23
+ onTabChange=(action "tabChanged")
22
24
  actionsInMenu=actionsInMenu}}
23
25
 
24
26
  <div class="action-panel">
@@ -183,13 +183,12 @@ module Logster
183
183
  end
184
184
 
185
185
  if similar
186
- has_env = !similar.env.nil? && !similar.env.empty?
187
- if similar.count < Logster::MAX_GROUPING_LENGTH && !has_env
186
+ if similar.count < Logster::MAX_GROUPING_LENGTH
188
187
  similar.env = get_env(similar.key) || {}
189
188
  end
190
189
  save_env = similar.merge_similar_message(message)
191
190
 
192
- replace_and_bump(similar, save_env: save_env || has_env)
191
+ replace_and_bump(similar, save_env: save_env)
193
192
  similar
194
193
  else
195
194
  save message
@@ -11,7 +11,8 @@ module Logster
11
11
  :enable_js_error_reporting,
12
12
  :environments,
13
13
  :rate_limit_error_reporting,
14
- :web_title
14
+ :web_title,
15
+ :maximum_message_size_bytes
15
16
  )
16
17
 
17
18
  attr_writer :subdirectory
@@ -25,6 +26,7 @@ module Logster
25
26
  @enable_custom_patterns_via_ui = false
26
27
  @rate_limit_error_reporting = true
27
28
  @enable_js_error_reporting = true
29
+ @maximum_message_size_bytes = 60_000
28
30
 
29
31
  @allow_grouping = false
30
32
 
@@ -4,6 +4,7 @@ require 'securerandom'
4
4
  module Logster
5
5
 
6
6
  MAX_GROUPING_LENGTH = 50
7
+ MAX_MESSAGE_LENGTH = 600
7
8
 
8
9
  class Message
9
10
  LOGSTER_ENV = "_logster_env".freeze
@@ -21,13 +22,14 @@ module Logster
21
22
  application_version
22
23
  }
23
24
 
24
- attr_accessor :timestamp, :severity, :progname, :message, :key, :backtrace, :count, :env, :protected, :first_timestamp
25
+ attr_accessor :timestamp, :severity, :progname, :key, :backtrace, :count, :protected, :first_timestamp
26
+ attr_reader :message, :env
25
27
 
26
28
  def initialize(severity, progname, message, timestamp = nil, key = nil, count: 1)
27
29
  @timestamp = timestamp || get_timestamp
28
30
  @severity = severity
29
31
  @progname = progname
30
- @message = message
32
+ @message = truncate_message(message)
31
33
  @key = key || SecureRandom.hex
32
34
  @backtrace = nil
33
35
  @count = count || 1
@@ -53,6 +55,10 @@ module Logster
53
55
  h
54
56
  end
55
57
 
58
+ def message=(m)
59
+ @message = truncate_message(m)
60
+ end
61
+
56
62
  def to_json(opts = nil)
57
63
  exclude_env = Hash === opts && opts.delete(:exclude_env)
58
64
  JSON.fast_generate(to_h(exclude_env: exclude_env), opts)
@@ -74,6 +80,7 @@ module Logster
74
80
  end
75
81
 
76
82
  def env=(env)
83
+ @env_json = nil
77
84
  @env = self.class.scrub_params(env)
78
85
  end
79
86
 
@@ -90,6 +97,7 @@ module Logster
90
97
  else
91
98
  env = self.class.default_env.merge(env)
92
99
  end
100
+ @env_json = nil
93
101
  @env = Message.populate_from_env(env)
94
102
  end
95
103
 
@@ -140,6 +148,10 @@ module Logster
140
148
  self.count += other.count || 1
141
149
  return false if self.count > Logster::MAX_GROUPING_LENGTH
142
150
 
151
+ size = self.to_json(exclude_env: true).bytesize + self.env_json.bytesize
152
+ extra_env_size = other.env_json.bytesize
153
+ return false if size + extra_env_size > Logster.config.maximum_message_size_bytes
154
+
143
155
  other_env = JSON.load JSON.fast_generate other.env
144
156
  if Hash === other_env && !other_env.key?("time")
145
157
  other_env["time"] = other.timestamp
@@ -153,6 +165,7 @@ module Logster
153
165
  else
154
166
  Array === other_env ? self.env = [self.env, *other_env] : self.env = [self.env, other_env]
155
167
  end
168
+ @env_json = nil
156
169
  true
157
170
  end
158
171
 
@@ -214,6 +227,10 @@ module Logster
214
227
  end
215
228
  end
216
229
 
230
+ def env_json
231
+ @env_json ||= (self.env || {}).to_json
232
+ end
233
+
217
234
  def self.scrub_params(params)
218
235
  if Array === params
219
236
  params.map! { |p| scrub_params(p) }
@@ -233,6 +250,11 @@ module Logster
233
250
 
234
251
  protected
235
252
 
253
+ def truncate_message(msg)
254
+ return msg unless msg
255
+ msg.size <= MAX_MESSAGE_LENGTH ? msg : msg[0...MAX_MESSAGE_LENGTH] + "..."
256
+ end
257
+
236
258
  def get_timestamp
237
259
  (Time.new.to_f * 1000).to_i
238
260
  end
@@ -156,6 +156,14 @@ module Logster
156
156
  [200, {}, ["OK"]]
157
157
  elsif resource == "/"
158
158
  [200, { "Content-Type" => "text/html; charset=utf-8" }, [body(preload_json)]]
159
+ elsif resource =~ /\/fetch-env\/([0-9a-f]+)\.json$/
160
+ key = $1
161
+ env = Logster.store.get_env(key)
162
+ if env
163
+ [200, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.generate(env)]]
164
+ else
165
+ not_found
166
+ end
159
167
  else
160
168
  not_found
161
169
  end
@@ -190,6 +198,8 @@ module Logster
190
198
  search = (parse_regex(search) || search) if params["regex_search"] == "true"
191
199
  opts[:search] = search
192
200
  end
201
+ search = opts[:search]
202
+ opts[:with_env] = (String === search && search.size > 0) || Regexp === search
193
203
 
194
204
  payload = {
195
205
  messages: @store.latest(opts),
@@ -24,6 +24,7 @@ module Logster
24
24
  return true if @redis.hget(solved_key, solved)
25
25
  end
26
26
  end
27
+ apply_max_size_limit(message)
27
28
 
28
29
  @redis.multi do
29
30
  @redis.hset(grouping_key, message.grouping_key, message.key)
@@ -64,7 +65,7 @@ module Logster
64
65
 
65
66
  @redis.multi do
66
67
  @redis.hset(hash_key, message.key, message.to_json(exclude_env: true))
67
- @redis.hset(env_key, message.key, (message.env || {}).to_json) if save_env
68
+ @redis.hset(env_key, message.key, message.env_json) if save_env
68
69
  @redis.lrem(list_key, -1, message.key)
69
70
  @redis.rpush(list_key, message.key)
70
71
  end
@@ -98,6 +99,7 @@ module Logster
98
99
  before = opts[:before]
99
100
  after = opts[:after]
100
101
  search = opts[:search]
102
+ with_env = opts.key?(:with_env) ? opts[:with_env] : true
101
103
 
102
104
  start, finish = find_location(before, after, limit)
103
105
 
@@ -110,7 +112,7 @@ module Logster
110
112
  begin
111
113
  keys = @redis.lrange(list_key, start, finish) || []
112
114
  break unless keys && (keys.count > 0)
113
- rows = bulk_get(keys)
115
+ rows = bulk_get(keys, with_env: with_env)
114
116
 
115
117
  temp = []
116
118
 
@@ -204,14 +206,16 @@ module Logster
204
206
  bulk_get(@redis.lrange(list_key, 0, -1))
205
207
  end
206
208
 
207
- def bulk_get(message_keys)
208
- envs = @redis.hmget(env_key, message_keys)
209
- @redis.hmget(hash_key, message_keys).map!.with_index do |json, ind|
209
+ def bulk_get(message_keys, with_env: true)
210
+ envs = @redis.mapped_hmget(env_key, *message_keys) if with_env
211
+ @redis.hmget(hash_key, message_keys).map! do |json|
210
212
  message = Message.from_json(json)
211
- env = envs[ind]
212
- if !message.env || message.env.size == 0
213
- env = env && env.size > 0 ? ::JSON.parse(env) : {}
214
- message.env = env
213
+ if with_env
214
+ env = envs[message.key]
215
+ if !message.env || message.env.size == 0
216
+ env = env && env.size > 0 ? ::JSON.parse(env) : {}
217
+ message.env = env
218
+ end
215
219
  end
216
220
  message
217
221
  end
@@ -337,7 +341,7 @@ module Logster
337
341
 
338
342
  def update_message(message)
339
343
  @redis.hset(hash_key, message.key, message.to_json(exclude_env: true))
340
- @redis.hset(env_key, message.key, (message.env || {}).to_json)
344
+ @redis.hset(env_key, message.key, message.env_json)
341
345
  if message.protected
342
346
  @redis.sadd(protected_key, message.key)
343
347
  else
@@ -513,6 +517,22 @@ module Logster
513
517
 
514
518
  private
515
519
 
520
+ def apply_max_size_limit(message)
521
+ size = message.to_json(exclude_env: true).bytesize
522
+ env_size = message.env_json.bytesize
523
+ max_size = Logster.config.maximum_message_size_bytes
524
+ if size + env_size > max_size
525
+ # env is most likely the reason for the large size
526
+ # truncate it so the overall size is < the limit
527
+ if Array === message.env
528
+ # the - 1 at the end ensures the size goes a little bit below the limit
529
+ truncate_at = (message.env.size.to_f * max_size.to_f / (env_size + size)).to_i - 1
530
+ truncate_at = 1 if truncate_at < 1
531
+ message.env = message.env[0...truncate_at]
532
+ end
533
+ end
534
+ end
535
+
516
536
  def register_rate_limit(severities, limit, duration, callback)
517
537
  severities = [severities] unless severities.is_a?(Array)
518
538
  redis = (@redis_raw_connection && @redis_prefix) ? @redis_raw_connection : @redis
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Logster
4
- VERSION = "2.4.0"
4
+ VERSION = "2.4.1"
5
5
  end
@@ -328,4 +328,44 @@ class TestViewer < Minitest::Test
328
328
  assert_equal(404, response.status, "#{path} should have 404'ed")
329
329
  end
330
330
  end
331
+
332
+ def test_messages_endpoint_doesnt_include_envs_when_search_term_absent
333
+ Logster.store.clear_all
334
+ env = { "b" => 1, "c" => 2 }
335
+ msg = Logster.store.report(Logger::INFO, "test", "something hello", env: env)
336
+ response = request.get("/logsie/messages.json")
337
+ assert_equal(200, response.status)
338
+ messages = JSON.parse(response.body)["messages"]
339
+ assert_equal(1, messages.size)
340
+ msg = messages.first
341
+ assert_equal("something hello", msg["message"])
342
+ assert_nil(msg["env"])
343
+ end
344
+
345
+ def test_messages_endpoint_includes_env_when_there_is_search_term
346
+ Logster.store.clear_all
347
+ env = { "b" => 1, "c" => 2 }
348
+ msg = Logster.store.report(Logger::INFO, "test", "something hello", env: env)
349
+ response = request.get("/logsie/messages.json?search=something")
350
+ assert_equal(200, response.status)
351
+ messages = JSON.parse(response.body)["messages"]
352
+ assert_equal(1, messages.size)
353
+ msg = messages.first
354
+ assert_equal("something hello", msg["message"])
355
+ assert_includes(msg["env"].values, 1, 2)
356
+ end
357
+
358
+ def test_fetch_env_returns_env_associated_with_message
359
+ env = { "b" => 1, "c" => 2 }
360
+ msg = Logster.store.report(Logger::INFO, "test", "something whatever store", env: env)
361
+ response = request.get("/logsie/fetch-env/#{msg.key}.json")
362
+ assert_equal(200, response.status)
363
+ res = JSON.parse(response.body)
364
+ assert_includes(res.values, 1, 2)
365
+ end
366
+
367
+ def test_fetch_env_returns_404_when_invalid_key
368
+ response = request.get("/logsie/fetch-env/123456abc.json")
369
+ assert_equal(404, response.status)
370
+ end
331
371
  end
@@ -148,4 +148,28 @@ class TestMessage < MiniTest::Test
148
148
  assert_includes(msg.to_json, test_hash.to_json)
149
149
  refute_includes(msg.to_json(exclude_env: true), test_hash.to_json)
150
150
  end
151
+
152
+ def test_title_is_truncated_when_too_large
153
+ msg = Logster::Message.new(0, "", "a" * 1000)
154
+ # 3 is the ... at the end to indicate truncated message
155
+ assert_equal(600 + 3, msg.message.size)
156
+ end
157
+
158
+ def test_env_is_not_merged_into_similar_message_if_size_will_be_too_large
159
+ default = Logster.config.maximum_message_size_bytes
160
+ Logster.config.maximum_message_size_bytes = 1000
161
+ message = Logster::Message.new(Logger::INFO, "test", "message", count: 13)
162
+ env = [{ key1: "this is my first key", key2: "this is my second key" }] * 13
163
+ message.env = env
164
+
165
+ message2 = Logster::Message.new(Logger::INFO, "test", "message")
166
+ message2.env = env.first
167
+ message.merge_similar_message(message2)
168
+
169
+ # env isn't merged, but count is incremented
170
+ assert_equal(13, message.env.size)
171
+ assert_equal(14, message.count)
172
+ ensure
173
+ Logster.config.maximum_message_size_bytes = default
174
+ end
151
175
  end
@@ -705,6 +705,21 @@ class TestRedisStore < Minitest::Test
705
705
  end
706
706
  end
707
707
 
708
+ def test_store_trims_too_big_envs
709
+ default = Logster.config.maximum_message_size_bytes
710
+ Logster.config.maximum_message_size_bytes = 1000
711
+ message = Logster::Message.new(Logger::INFO, "test", "message")
712
+ env = [{ key1: "this is my first key", key2: "this is my second key" }] * 40
713
+ message.env = env
714
+ @store.save(message)
715
+ trimmed_message = @store.latest.first
716
+ assert_equal(13, trimmed_message.env.size)
717
+ size = message.to_json(exclude_env: true).bytesize + message.env_json.bytesize
718
+ assert_operator(1000, :>, size)
719
+ ensure
720
+ Logster.config.maximum_message_size_bytes = default
721
+ end
722
+
708
723
  private
709
724
 
710
725
  def reset_redis
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logster
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 2.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - UI for viewing logs in Rack
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-10 00:00:00.000000000 Z
11
+ date: 2019-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler