)]}'
{"etc/monasca.ini":[{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":10,"context_line":""},{"line_number":11,"context_line":"#kafka dispatcher parameters"},{"line_number":12,"context_line":"kafka.uri\u003d192.168.1.191:9092"},{"line_number":13,"context_line":"kafka.topic\u003dmonasca"},{"line_number":14,"context_line":"kafka.max_retry \u003d 1"},{"line_number":15,"context_line":"kafka.async \u003d True"},{"line_number":16,"context_line":"kafka.compact \u003d False"}],"source_content_type":"text/x-properties","patch_set":1,"id":"fa98f980_5c0c8c3b","line":13,"updated":"2014-09-11 20:57:16.000000000","message":"The default topic name in Monasca for metrics is \"metrics\"","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":10,"context_line":""},{"line_number":11,"context_line":"#kafka dispatcher parameters"},{"line_number":12,"context_line":"kafka.uri\u003d192.168.1.191:9092"},{"line_number":13,"context_line":"kafka.topic\u003dmonasca"},{"line_number":14,"context_line":"kafka.max_retry \u003d 1"},{"line_number":15,"context_line":"kafka.async \u003d True"},{"line_number":16,"context_line":"kafka.compact \u003d False"}],"source_content_type":"text/x-properties","patch_set":1,"id":"fa98f980_613d248f","line":13,"in_reply_to":"fa98f980_5c0c8c3b","updated":"2014-09-11 21:31:36.000000000","message":"this is just an example. change to whatever you like for production. I can make the default to be metrics.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":12,"context_line":"kafka.uri\u003d192.168.1.191:9092"},{"line_number":13,"context_line":"kafka.topic\u003dmonasca"},{"line_number":14,"context_line":"kafka.max_retry \u003d 1"},{"line_number":15,"context_line":"kafka.async \u003d True"},{"line_number":16,"context_line":"kafka.compact \u003d False"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":""}],"source_content_type":"text/x-properties","patch_set":1,"id":"fa98f980_e1003704","line":15,"updated":"2014-09-11 20:57:16.000000000","message":"Async is dangerous because the metric could be lost. With async messages the messages are buffered in-memory by the client.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":12,"context_line":"kafka.uri\u003d192.168.1.191:9092"},{"line_number":13,"context_line":"kafka.topic\u003dmonasca"},{"line_number":14,"context_line":"kafka.max_retry \u003d 1"},{"line_number":15,"context_line":"kafka.async \u003d True"},{"line_number":16,"context_line":"kafka.compact \u003d False"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":""}],"source_content_type":"text/x-properties","patch_set":1,"id":"fa98f980_e16f5490","line":15,"in_reply_to":"fa98f980_e1003704","updated":"2014-09-11 21:31:36.000000000","message":"can change the default to False.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":13,"context_line":"kafka.topic\u003dmonasca"},{"line_number":14,"context_line":"kafka.max_retry \u003d 1"},{"line_number":15,"context_line":"kafka.async \u003d True"},{"line_number":16,"context_line":"kafka.compact \u003d False"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"[pipeline:main]"}],"source_content_type":"text/x-properties","patch_set":1,"id":"fa98f980_a1238fbb","line":16,"updated":"2014-09-11 20:57:16.000000000","message":"Currently, the rest of the Monasca implementation doesn\u0027t support a \"compact\" mode.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":13,"context_line":"kafka.topic\u003dmonasca"},{"line_number":14,"context_line":"kafka.max_retry \u003d 1"},{"line_number":15,"context_line":"kafka.async \u003d True"},{"line_number":16,"context_line":"kafka.compact \u003d False"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"[pipeline:main]"}],"source_content_type":"text/x-properties","patch_set":1,"id":"fa98f980_810cc8ed","line":16,"in_reply_to":"fa98f980_a1238fbb","updated":"2014-09-11 21:31:36.000000000","message":"so the default is correct. messages will be unpacked and send one by one.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":35,"context_line":"host \u003d 0.0.0.0"},{"line_number":36,"context_line":"port \u003d 9090"},{"line_number":37,"context_line":"workers \u003d 1"},{"line_number":38,"context_line":"proc_name \u003d monasca"}],"source_content_type":"text/x-properties","patch_set":1,"id":"fa98f980_fc2700b4","line":38,"updated":"2014-09-11 20:57:16.000000000","message":"Should this be monasca-api?","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":35,"context_line":"host \u003d 0.0.0.0"},{"line_number":36,"context_line":"port \u003d 9090"},{"line_number":37,"context_line":"workers \u003d 1"},{"line_number":38,"context_line":"proc_name \u003d monasca"}],"source_content_type":"text/x-properties","patch_set":1,"id":"fa98f980_0100d8a9","line":38,"in_reply_to":"fa98f980_fc2700b4","updated":"2014-09-11 21:31:36.000000000","message":"sure.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"}],"monasca/dispatcher/file.py":[{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":29,"context_line":"        self.conf \u003d conf"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"    def define_routes(self, app):"},{"line_number":32,"context_line":"        app.add_route(\u0027/datapoints/{id}\u0027, FileDataPoint())"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_7c4cf042","line":32,"updated":"2014-09-11 20:57:16.000000000","message":"Monasca doesn\u0027t have a \"datapoints\" resource right now and this code.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":29,"context_line":"        self.conf \u003d conf"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"    def define_routes(self, app):"},{"line_number":32,"context_line":"        app.add_route(\u0027/datapoints/{id}\u0027, FileDataPoint())"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_5d9c6ac0","line":32,"updated":"2014-09-12 17:42:51.000000000","message":"This is dead-code and shouldn\u0027t be checked in. It doesn\u0027t implement anything.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"}],"monasca/dispatcher/kafka_queue.py":[{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":71,"context_line":"        self.client \u003d None"},{"line_number":72,"context_line":"        self.producer \u003d None"},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"    def _init_kafka(self):"},{"line_number":75,"context_line":"        if self.uri:"},{"line_number":76,"context_line":"            try:"},{"line_number":77,"context_line":"                if self.client:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_c22235a2","line":74,"updated":"2014-09-12 17:42:51.000000000","message":"Agree with Jonathan\u0027s POST above. Initialization logic should be done in the constructor following the Resource Initialization is Acquisition principle in OO design. In other words create objects in their fully constructed state. Don\u0027t do partial object creation. That would take the code below\n\n               if not self.client or not self.producer:\n                    self._init_kafka()\n\nand it would get moved into the constructor as just\n\nself._init_kafka() and be done once and never need to be looked at again.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":1976,"name":"Jonathan Halterman","email":"jhalterman@hp.com","username":"jhalterman"},"change_message_id":"4175dc50d7c5b846efa08de706a6073a04092b33","unresolved":false,"context_lines":[{"line_number":71,"context_line":"        self.client \u003d None"},{"line_number":72,"context_line":"        self.producer \u003d None"},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"    def _init_kafka(self):"},{"line_number":75,"context_line":"        if self.uri:"},{"line_number":76,"context_line":"            try:"},{"line_number":77,"context_line":"                if self.client:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_7c26b0cf","line":74,"updated":"2014-09-11 20:53:00.000000000","message":"Consider initializing the Kafka client/producer once for all requests","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"b41f11ba17680fabe737021f7584cfd63bd34431","unresolved":false,"context_lines":[{"line_number":71,"context_line":"        self.client \u003d None"},{"line_number":72,"context_line":"        self.producer \u003d None"},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"    def _init_kafka(self):"},{"line_number":75,"context_line":"        if self.uri:"},{"line_number":76,"context_line":"            try:"},{"line_number":77,"context_line":"                if self.client:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_eb81c3c3","line":74,"in_reply_to":"fa98f980_c22235a2","updated":"2014-09-14 02:06:49.000000000","message":"that will only work in a perfect world. Think about this, you have this service\nrunning, after awhile, your kafka goes down, few minutes later, your kafka \ncomes back up. The client has gone stale, it won\u0027t be able to recover. \nThis is particularly important for a distributed system. the implementation like\nthis can actually tolerate the kafka goes down and back up.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":91,"context_line":"                      \"configured.\")"},{"line_number":92,"context_line":""},{"line_number":93,"context_line":"    @resource_api.Restify(path\u003d\u0027/v2.0/metrics\u0027, method\u003d\u0027post\u0027)"},{"line_number":94,"context_line":"    def on_post_metrics(self, req, res):"},{"line_number":95,"context_line":"        LOG.debug(\u0027Getting the call.\u0027)"},{"line_number":96,"context_line":"        msg \u003d \u0027\u0027"},{"line_number":97,"context_line":"        while True:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_a21d3164","line":94,"updated":"2014-09-12 17:42:51.000000000","message":"That is exactly what I imagine. A class called MetricResource with several methods in it corresponding to each HTTP VERB that is supported. One method for POST and one for GET, ... The use of classes to model resources really helps out with grouping.\n\nIndependent of modeling resources as classes putting on_post_metrics in side a class called KafkaDispatcher is clearly poor OO design. \n\nThink about in the future when I want to have RabbitMQDispatcher or MockDispatcher.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":91,"context_line":"                      \"configured.\")"},{"line_number":92,"context_line":""},{"line_number":93,"context_line":"    @resource_api.Restify(path\u003d\u0027/v2.0/metrics\u0027, method\u003d\u0027post\u0027)"},{"line_number":94,"context_line":"    def on_post_metrics(self, req, res):"},{"line_number":95,"context_line":"        LOG.debug(\u0027Getting the call.\u0027)"},{"line_number":96,"context_line":"        msg \u003d \u0027\u0027"},{"line_number":97,"context_line":"        while True:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_9e0b4923","line":94,"updated":"2014-09-11 20:57:16.000000000","message":"This method should be moved into a resource class called something like \"MetricsResource\" with a method called \"on_post\".\n\nAs we add other resource, like Measurements and Alarms, they should all be in their own files/classes.\n\nThe KafkaDIspatcher should purely be about sending messages to Kafka and initialized one somewhere and passed into a resource class for MetricsResource and everything else.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":91,"context_line":"                      \"configured.\")"},{"line_number":92,"context_line":""},{"line_number":93,"context_line":"    @resource_api.Restify(path\u003d\u0027/v2.0/metrics\u0027, method\u003d\u0027post\u0027)"},{"line_number":94,"context_line":"    def on_post_metrics(self, req, res):"},{"line_number":95,"context_line":"        LOG.debug(\u0027Getting the call.\u0027)"},{"line_number":96,"context_line":"        msg \u003d \u0027\u0027"},{"line_number":97,"context_line":"        while True:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_deadd132","line":94,"in_reply_to":"fa98f980_9e0b4923","updated":"2014-09-11 21:31:36.000000000","message":"imagine you have many other methods to handle different http requests at\ndifferent endpoint. Really not like having to use the method name to do that.\nthat was whole point of having a subclass.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"b41f11ba17680fabe737021f7584cfd63bd34431","unresolved":false,"context_lines":[{"line_number":91,"context_line":"                      \"configured.\")"},{"line_number":92,"context_line":""},{"line_number":93,"context_line":"    @resource_api.Restify(path\u003d\u0027/v2.0/metrics\u0027, method\u003d\u0027post\u0027)"},{"line_number":94,"context_line":"    def on_post_metrics(self, req, res):"},{"line_number":95,"context_line":"        LOG.debug(\u0027Getting the call.\u0027)"},{"line_number":96,"context_line":"        msg \u003d \u0027\u0027"},{"line_number":97,"context_line":"        while True:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_4b6acf1a","line":94,"in_reply_to":"fa98f980_a21d3164","updated":"2014-09-14 02:06:49.000000000","message":"I will give you an example on why this is a current limitation of falcon. and why\nresource_api.py (which is an extension to the falcon.API) corrected that problem. you will see it in next patch set.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":98,"context_line":"            chunk \u003d req.stream.read(1024)"},{"line_number":99,"context_line":"            if not chunk:"},{"line_number":100,"context_line":"                break"},{"line_number":101,"context_line":"            msg \u003d msg.join(chunk)"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"        if msg:"},{"line_number":104,"context_line":"            if self.drop_data:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_e2f8197e","line":101,"updated":"2014-09-12 17:42:51.000000000","message":"From the Falcon API documentation for stream\n\nEither a file-like object with a read() method that takes an optional size argument and returns a block of bytes, or an iterable object, representing response content, and yielding blocks as byte strings. Falcon will use wsgi.file_wrapper, if provided by the WSGI server, in order to efficiently serve file-like objects.\n\nWhat that says is that the size parameter is optional. I read that to mean if it isn\u0027t supplied the amount of data to read will be computed. That is what I wrote in my implementation which I tested and it worked.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":98,"context_line":"            chunk \u003d req.stream.read(1024)"},{"line_number":99,"context_line":"            if not chunk:"},{"line_number":100,"context_line":"                break"},{"line_number":101,"context_line":"            msg \u003d msg.join(chunk)"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"        if msg:"},{"line_number":104,"context_line":"            if self.drop_data:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_7e06a51d","line":101,"updated":"2014-09-11 20:57:16.000000000","message":"In my performance analysis this sort of loop to copy the data over was slower than just reading it all in at once.\n\nJust wondering why this was added. For example, was it performance related or some other reason.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":98,"context_line":"            chunk \u003d req.stream.read(1024)"},{"line_number":99,"context_line":"            if not chunk:"},{"line_number":100,"context_line":"                break"},{"line_number":101,"context_line":"            msg \u003d msg.join(chunk)"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"        if msg:"},{"line_number":104,"context_line":"            if self.drop_data:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_9e6fc9fb","line":101,"in_reply_to":"fa98f980_7e06a51d","updated":"2014-09-11 21:31:36.000000000","message":"the problem is that you do not know how much to read. performance wise,\nthere is no difference.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":100,"context_line":"                break"},{"line_number":101,"context_line":"            msg \u003d msg.join(chunk)"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"        if msg:"},{"line_number":104,"context_line":"            if self.drop_data:"},{"line_number":105,"context_line":"                res.status \u003d falcon.HTTP_204"},{"line_number":106,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_c2007568","line":103,"updated":"2014-09-12 17:42:51.000000000","message":"Cite me a reference on that. Here is one for you to read. http://stackoverflow.com/questions/36707/should-a-function-have-only-one-return-statement\n\nAll these indented blocks make it much harder to read the code and for something like input validation in which it is very clear what is being done and tested and that you don\u0027t want to continue unless input validation has been succesful it is much nicer to have at the top.\n\nIf this was a return statement in the middle of several nested blocks of code, that would be different, and I would agree doing something like that should be avoided.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":100,"context_line":"                break"},{"line_number":101,"context_line":"            msg \u003d msg.join(chunk)"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"        if msg:"},{"line_number":104,"context_line":"            if self.drop_data:"},{"line_number":105,"context_line":"                res.status \u003d falcon.HTTP_204"},{"line_number":106,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_bc0018ac","line":103,"updated":"2014-09-11 20:57:16.000000000","message":"If you wrote this as \n\nif not msg:\n    res.status \u003d ?\n    return\n\nyou wouldn\u0027t have to indent everything else in this method.\n\nI\u0027m not exactly sure what the Java implementation does in this case, but I would be happy to test it out.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":100,"context_line":"                break"},{"line_number":101,"context_line":"            msg \u003d msg.join(chunk)"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"        if msg:"},{"line_number":104,"context_line":"            if self.drop_data:"},{"line_number":105,"context_line":"                res.status \u003d falcon.HTTP_204"},{"line_number":106,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_7e414562","line":103,"in_reply_to":"fa98f980_bc0018ac","updated":"2014-09-11 21:31:36.000000000","message":"in python, I believe return in the middle of a method is a bad practice. Some\nmay like that style. I do not.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":103,"context_line":"        if msg:"},{"line_number":104,"context_line":"            if self.drop_data:"},{"line_number":105,"context_line":"                res.status \u003d falcon.HTTP_204"},{"line_number":106,"context_line":"            else:"},{"line_number":107,"context_line":"                if not self.client or not self.producer:"},{"line_number":108,"context_line":"                    self._init_kafka()"},{"line_number":109,"context_line":"                for i in range(0, self.max_retry):"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_e26d7933","line":106,"updated":"2014-09-12 17:42:51.000000000","message":"I understand that we talked about it, that doesn\u0027t mean I think that it is a good idea. \n\nAnyway, I\u0027m kinda wondering how that would work and what would be implemented in the end using the middle-ware approach.\n\nAnother way that seems much more straight-forward is to just have a check for\n\nif is_input_validation:\n    do_input_validation()\n\nrather than implementing as middle-ware. The code is nice and localized in that case.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"b2bde97c8cafd06deec0e8147030bc88ce0fb75a","unresolved":false,"context_lines":[{"line_number":103,"context_line":"        if msg:"},{"line_number":104,"context_line":"            if self.drop_data:"},{"line_number":105,"context_line":"                res.status \u003d falcon.HTTP_204"},{"line_number":106,"context_line":"            else:"},{"line_number":107,"context_line":"                if not self.client or not self.producer:"},{"line_number":108,"context_line":"                    self._init_kafka()"},{"line_number":109,"context_line":"                for i in range(0, self.max_retry):"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_fe729548","line":106,"updated":"2014-09-11 21:03:50.000000000","message":"There needs to be some input validation on the message prior to doing any further processing on it.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"b6ffe5ea7e617503b1568e9eef96abf649ff09b4","unresolved":false,"context_lines":[{"line_number":103,"context_line":"        if msg:"},{"line_number":104,"context_line":"            if self.drop_data:"},{"line_number":105,"context_line":"                res.status \u003d falcon.HTTP_204"},{"line_number":106,"context_line":"            else:"},{"line_number":107,"context_line":"                if not self.client or not self.producer:"},{"line_number":108,"context_line":"                    self._init_kafka()"},{"line_number":109,"context_line":"                for i in range(0, self.max_retry):"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_fd9a7b12","line":106,"in_reply_to":"fa98f980_e26d7933","updated":"2014-09-12 20:20:31.000000000","message":"Roland, I would like you to read wsgi tutorial. Which will help you to\nunderstand this. Using a code here will not allow you to use configuration\nto take away these validations. I will write a small middleware to demostrate\nhow this is done. Actually there are already two middlewares in the code.\nYou can use it in the wsgi pipeline to do things. This way, use it or not is\na configuration choice, not a code choice.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":103,"context_line":"        if msg:"},{"line_number":104,"context_line":"            if self.drop_data:"},{"line_number":105,"context_line":"                res.status \u003d falcon.HTTP_204"},{"line_number":106,"context_line":"            else:"},{"line_number":107,"context_line":"                if not self.client or not self.producer:"},{"line_number":108,"context_line":"                    self._init_kafka()"},{"line_number":109,"context_line":"                for i in range(0, self.max_retry):"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_fe2b7592","line":106,"in_reply_to":"fa98f980_fe729548","updated":"2014-09-11 21:31:36.000000000","message":"we talked about this. adding your own middle ware to do that.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":106,"context_line":"            else:"},{"line_number":107,"context_line":"                if not self.client or not self.producer:"},{"line_number":108,"context_line":"                    self._init_kafka()"},{"line_number":109,"context_line":"                for i in range(0, self.max_retry):"},{"line_number":110,"context_line":"                    try:"},{"line_number":111,"context_line":"                        LOG.debug(\u0027Start sending messages to kafka.\u0027)"},{"line_number":112,"context_line":"                        if self.compact:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_9c24340e","line":109,"updated":"2014-09-11 20:57:16.000000000","message":"Do you really want to do manual retries like this?\n\nI think it would be OK to not retry at all and return a 500 or 503 error rather than retry at all.\n\nUnfortunately, I didn\u0027t see an option for retrying in the Python Kafka Client, but all this retry looping would be repeated everywhere if we did this.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":106,"context_line":"            else:"},{"line_number":107,"context_line":"                if not self.client or not self.producer:"},{"line_number":108,"context_line":"                    self._init_kafka()"},{"line_number":109,"context_line":"                for i in range(0, self.max_retry):"},{"line_number":110,"context_line":"                    try:"},{"line_number":111,"context_line":"                        LOG.debug(\u0027Start sending messages to kafka.\u0027)"},{"line_number":112,"context_line":"                        if self.compact:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_c2a15547","line":109,"updated":"2014-09-12 17:42:51.000000000","message":"So, I think retry logic is desirable.\n\nMy preference would be then to have an interface for talking to queues that has a method in it called something like \"send_messages\"\n\nThe Kafka implementation of that would implement the retry logic:\n\nclass KafkaDispatcher(object):\n    self.producer \u003d ...\n\n    def send_messages(...):\n        while True:\n            self.producer.send_messages(...)\n            ...\n\nThis way we don\u0027t end-up repeating the same exact code and the same indented code block in every single method that handles a http request.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":106,"context_line":"            else:"},{"line_number":107,"context_line":"                if not self.client or not self.producer:"},{"line_number":108,"context_line":"                    self._init_kafka()"},{"line_number":109,"context_line":"                for i in range(0, self.max_retry):"},{"line_number":110,"context_line":"                    try:"},{"line_number":111,"context_line":"                        LOG.debug(\u0027Start sending messages to kafka.\u0027)"},{"line_number":112,"context_line":"                        if self.compact:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_a10b8c22","line":109,"in_reply_to":"fa98f980_9c24340e","updated":"2014-09-11 21:31:36.000000000","message":"I would think so. fail faster is fine as well. Trying to be nice.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":110,"context_line":"                    try:"},{"line_number":111,"context_line":"                        LOG.debug(\u0027Start sending messages to kafka.\u0027)"},{"line_number":112,"context_line":"                        if self.compact:"},{"line_number":113,"context_line":"                            self.producer.send_messages(self.topic, msg)"},{"line_number":114,"context_line":"                        else:"},{"line_number":115,"context_line":"                            data \u003d json.loads(msg)"},{"line_number":116,"context_line":"                            LOG.debug(\u0027Msg parsed successfully.\u0027)"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_428d65d2","line":113,"updated":"2014-09-12 17:42:51.000000000","message":"It isn\u0027t an option that works today anywhere in the rest of the Monasca system.\n\nWhy are we adding options and code that doesn\u0027t work?\n\nIf/when we get to doing something like this we can add it and completely implement it in the rest of the system. I\u0027m not accepting any partially implemented options and code.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":110,"context_line":"                    try:"},{"line_number":111,"context_line":"                        LOG.debug(\u0027Start sending messages to kafka.\u0027)"},{"line_number":112,"context_line":"                        if self.compact:"},{"line_number":113,"context_line":"                            self.producer.send_messages(self.topic, msg)"},{"line_number":114,"context_line":"                        else:"},{"line_number":115,"context_line":"                            data \u003d json.loads(msg)"},{"line_number":116,"context_line":"                            LOG.debug(\u0027Msg parsed successfully.\u0027)"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_5c3e4cdb","line":113,"updated":"2014-09-11 20:57:16.000000000","message":"Note, \"compact\" isn\u0027t supported in the rest of the Monasca implementation.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"b41f11ba17680fabe737021f7584cfd63bd34431","unresolved":false,"context_lines":[{"line_number":110,"context_line":"                    try:"},{"line_number":111,"context_line":"                        LOG.debug(\u0027Start sending messages to kafka.\u0027)"},{"line_number":112,"context_line":"                        if self.compact:"},{"line_number":113,"context_line":"                            self.producer.send_messages(self.topic, msg)"},{"line_number":114,"context_line":"                        else:"},{"line_number":115,"context_line":"                            data \u003d json.loads(msg)"},{"line_number":116,"context_line":"                            LOG.debug(\u0027Msg parsed successfully.\u0027)"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_8b703709","line":113,"in_reply_to":"fa98f980_428d65d2","updated":"2014-09-14 02:06:49.000000000","message":"it will be an option for our use case. Roland, remember you kept arguing that\nyou do not want to crack open a message? Why would I want to always do\nthat here? If you do not want to use, disable that. and default is False.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":110,"context_line":"                    try:"},{"line_number":111,"context_line":"                        LOG.debug(\u0027Start sending messages to kafka.\u0027)"},{"line_number":112,"context_line":"                        if self.compact:"},{"line_number":113,"context_line":"                            self.producer.send_messages(self.topic, msg)"},{"line_number":114,"context_line":"                        else:"},{"line_number":115,"context_line":"                            data \u003d json.loads(msg)"},{"line_number":116,"context_line":"                            LOG.debug(\u0027Msg parsed successfully.\u0027)"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_e1103450","line":113,"in_reply_to":"fa98f980_5c3e4cdb","updated":"2014-09-11 21:31:36.000000000","message":"just an option. if we really want to be fast, we should not parse here. \nwe discussed this before as well.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":117,"context_line":"                            if isinstance(data, list):"},{"line_number":118,"context_line":"                                for item in data:"},{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_624b4987","line":120,"updated":"2014-09-12 17:42:51.000000000","message":"Sure, there are ways of coding for this.\n\nClearly what is implemented will return a success to the client half-way through the list if they ended up with bad data in there.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":117,"context_line":"                            if isinstance(data, list):"},{"line_number":118,"context_line":"                                for item in data:"},{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_3c3988f2","line":120,"updated":"2014-09-11 20:57:16.000000000","message":"The problem with this loop is that for each metric it tries to convert to a string and send the metric, but if it fails an exception is caught down below in the ValueError exception block, which could occur partially through the list.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"5e0ac963900f9ea2edde40a46c698badd868cf0e","unresolved":false,"context_lines":[{"line_number":117,"context_line":"                            if isinstance(data, list):"},{"line_number":118,"context_line":"                                for item in data:"},{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_b51d5f11","line":120,"updated":"2014-09-13 13:04:19.000000000","message":"We\u0027ll have to discuss. I\u0027m not sure how the distributed unique ID fits in.\n\nMy preference is to fail the entire message or process it completely. If you fail the entire message, at least the client knows it was not processed and can try again, hopefully with a smaller message. \n\nThat is a good point about how we currently handle the Kafka messages though. The entire http request is not processed atomically in our current system as we add each metric to the queue separately. If Kafka goes down partially through, then we\u0027ll end-up in a partially processed state. \n\nThat would argue for passing the metrics in as arrays, which is what your \"compact\" option is for. So, I agree that this would be a good option to add. However, since the rest of the Monasca system doesn\u0027t support it yet, and we still will need the tenant ID, region, and creation_time, we still can\u0027t pass the original http request body exactly through the system.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":117,"context_line":"                            if isinstance(data, list):"},{"line_number":118,"context_line":"                                for item in data:"},{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_e13e74b7","line":120,"in_reply_to":"fa98f980_3c3988f2","updated":"2014-09-11 21:31:36.000000000","message":"not sure there is anything you can do though. if we receive a lot of message\nin one request and monasca requires send one by one. I thought this is what\nhp does. I would rather not to support this.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"b6ffe5ea7e617503b1568e9eef96abf649ff09b4","unresolved":false,"context_lines":[{"line_number":117,"context_line":"                            if isinstance(data, list):"},{"line_number":118,"context_line":"                                for item in data:"},{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_fd68bbf6","line":120,"in_reply_to":"fa98f980_624b4987","updated":"2014-09-12 20:20:31.000000000","message":"not really. the problem is that if you have many messages in one request.\nthey are all good ones in terms of the format, remember the validation\nmiddleware I was talking about. The problem is that if kafka goes down or this service goes down after first few messages are sent successfully. then you have a partial message sent, other part not, you can fail the entire request, but still you may end up with duplicate data in the system. Again, I argue that using the distributed unique id will ease this problem.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"b41f11ba17680fabe737021f7584cfd63bd34431","unresolved":false,"context_lines":[{"line_number":117,"context_line":"                            if isinstance(data, list):"},{"line_number":118,"context_line":"                                for item in data:"},{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_cb65df45","line":120,"in_reply_to":"fa98f980_b51d5f11","updated":"2014-09-14 02:06:49.000000000","message":"I am writing a validator for metric messages. You will see how that will work\nonce I have it uploaded.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"5e0ac963900f9ea2edde40a46c698badd868cf0e","unresolved":false,"context_lines":[{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_35640fb8","line":122,"updated":"2014-09-13 13:04:19.000000000","message":"It won\u0027t work with the rest of the current Monasca system as it is currently implemented. \n\nIn this porting effort I think we should first be maintaining a fully functional system as in the current components, whether they are Java or Python, all continue to work. We can then come back and re-visit message formats and see if there are any improvements that could or should be made.\n\nThe current message format required by the rest of the Monasca pipeline is a JSON message with a few parts in it.\n\n{\n    \"metric\": {The metric as a JSON object},\n    \"meta\": {\n        \"tenantId\": \"the tenant ID acquired via authentication with Keystone\",\n        \"region\": \"the region that the metric was submitted under\",\n    },\n    \"creation_time\": the time when the API received the metric as UNIX time\n}\n\nThat is what the rest of the current Monasca system expects.\n\nAs far as I recall in my performance analysis there wasn\u0027t a significant performance difference when just passing the metric through as compared to what is listed above.\n\nCurrently, we need the tenant ID, region and creation_time in the format above.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_3e009d00","line":122,"updated":"2014-09-11 20:57:16.000000000","message":"The message that is sent here does not match what is currently used in Monasca. In other words, this code doesn\u0027t work.\n\nWhat is required right now is something the following:\n\n{\"metric\":{\"name\":\"disk_space_utilization_perc\",\"dimensions\":{\"service\":\"monitoring\",\"device\":\"v-csdb-3\",\"hostname\":\"mini-mon\"},\"timestamp\":1410459284,\"value\":87.36112721917534},\"meta\":{\"tenantId\":\"3c1f6223f44d42c0b88623e75ed3c996\",\"region\":\"useast\"},\"creation_time\":1410459285}","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_025c3d4a","line":122,"updated":"2014-09-12 17:42:51.000000000","message":"This doesn\u0027t work with the rest of the Monasca system as it is currently defined. \n\nClearly this code was never tested with the rest of the Monasca system.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"b6ffe5ea7e617503b1568e9eef96abf649ff09b4","unresolved":false,"context_lines":[{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_201f765c","line":122,"in_reply_to":"fa98f980_025c3d4a","updated":"2014-09-12 20:20:31.000000000","message":"it posts the messages onto the queue. With your own validator in the pipeline,\nvalid message gets here and will be posted onto the queue. This code\nsupports sending message in bulk and one by one. I am not sure why it\nwon\u0027t work with rest of the Monasca system.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":11809,"name":"Craig Bryant","email":"craig.bryant@hpe.com","username":"craig-bryant"},"change_message_id":"d8815779fde579f764faf0de90f95d8cc0576671","unresolved":false,"context_lines":[{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_1db2c993","line":122,"in_reply_to":"fa98f980_2bdd8be0","updated":"2014-09-15 15:38:14.000000000","message":"You are looking at the external message format. The internal message format is augmented by tenantId and region because monasca is a multi-tenant solution. The tenantId is provided by Keystone based on the user and token (or password) that is used when the metric post is authenticated. The API is the only part of the system that can ascertain the correct tenantId so it adds it to the metric for the internal message format.\n\nThe region is used to specify which region the API server is running in. It will only be used when metrics from multiple regions are aggregated into a single database.\n\nThe timestamp is used to help track performance of the monasca system as the metric flows through the system. The Threshold Engine uses it specifically to know if metrics are being received in a timely manner so that the Threshold Engine does not mark alarms as being in the Undetermined state if it is still catching up on metrics after the Threshold Engine restarts.\n\nThis is the format that must be used on the kafka queue so that the rest of monasca functions correctly.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"43acad34186b8d2a8db451427219ed9e872ab764","unresolved":false,"context_lines":[{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_2bdd8be0","line":122,"in_reply_to":"fa98f980_35640fb8","updated":"2014-09-14 02:10:39.000000000","message":"The metric format I was looking at is this (from the API spec). Looks like what you indicated above is not the same as the spec. Any idea why?\nis meta in the place of dimensions or someone just changed the spec?\nis it creation_time or timestamp? I will use the above to write the validator.\n\n{  \n      \"name\":\"name1\",\n      \"dimensions\":{  \n         \"key1\":\"value1\",\n         \"key2\":\"value2\"\n      },\n      \"timestamp\":1405630174,\n      \"value\":1.0\n   },","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":119,"context_line":"                                    self.producer.send_messages("},{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_e16594e1","line":122,"in_reply_to":"fa98f980_3e009d00","updated":"2014-09-11 21:31:36.000000000","message":"it did not care. it is a json and it will send. validate the message in your\nvalidator. stop the flow before it reaches this point.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"167052384657eb2111d08fce18cd72b61c8df51c","unresolved":false,"context_lines":[{"line_number":120,"context_line":"                                        self.topic, json.dumps(item))"},{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"},{"line_number":126,"context_line":"                    except ValueError:"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_1873d04e","line":123,"updated":"2014-09-12 18:25:30.000000000","message":"One other point related to this is that we need extra information, such as the tenantId, region and creation_time included in the message that is published to Kafka. The full message is listed above. The persister and other down-stream components use the tenant ID as this is a multi-tenant system and the database schemas require this information too.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"},{"line_number":126,"context_line":"                    except ValueError:"},{"line_number":127,"context_line":"                        LOG.exception(\u0027Message is not valid json.\u0027)"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_dd3a1acc","line":124,"updated":"2014-09-12 17:42:51.000000000","message":"Keeping log files semi-usable and uncluttered is extremely useful. Think about this, there is a big that shows up in production. You want to enable debug level logging. \n\nIs it really important to you to have every message logged that is was successfully sent. If your code is deployed in production you\u0027ll fill up your log file and make it impossible to see the forest through the trees.\n\nI think logging the messages that weren\u0027t sent successfully might be OK, but every successful message, that isn\u0027t a DEBUG level logging IMHO, that would be trace level debugging.\n\nThe OpenStack community talks about appropriate log messages and how cluttered up the log files are already.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"},{"line_number":126,"context_line":"                    except ValueError:"},{"line_number":127,"context_line":"                        LOG.exception(\u0027Message is not valid json.\u0027)"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_dcc23c52","line":124,"updated":"2014-09-11 20:57:16.000000000","message":"This is a lot of debug logging messages which could really fill up the log file and make it very difficult to read when trying to debug.\n\nMaybe this log message and the one above should be moved to LOG.trace, but I\u0027m wondering if that should be reported?","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"},{"line_number":126,"context_line":"                    except ValueError:"},{"line_number":127,"context_line":"                        LOG.exception(\u0027Message is not valid json.\u0027)"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_a1a70c0a","line":124,"in_reply_to":"fa98f980_dcc23c52","updated":"2014-09-11 21:31:36.000000000","message":"set your log level higher.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"b6ffe5ea7e617503b1568e9eef96abf649ff09b4","unresolved":false,"context_lines":[{"line_number":121,"context_line":"                            else:"},{"line_number":122,"context_line":"                                self.producer.send_messages(self.topic, msg)"},{"line_number":123,"context_line":"                        res.status \u003d falcon.HTTP_204"},{"line_number":124,"context_line":"                        LOG.debug(\u0027Message posted successfully.\u0027)"},{"line_number":125,"context_line":"                        break"},{"line_number":126,"context_line":"                    except ValueError:"},{"line_number":127,"context_line":"                        LOG.exception(\u0027Message is not valid json.\u0027)"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_00535217","line":124,"in_reply_to":"fa98f980_dd3a1acc","updated":"2014-09-12 20:20:31.000000000","message":"I think at the beginning, when we try things, it is good to have more message.\nI added these to especially make you guys know what is going on when bad\nthings happen. I normally do not write that many debug messages as they\ndo cost some cpu cycles. We can remove some of these later.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":125,"context_line":"                        break"},{"line_number":126,"context_line":"                    except ValueError:"},{"line_number":127,"context_line":"                        LOG.exception(\u0027Message is not valid json.\u0027)"},{"line_number":128,"context_line":"                        res.status \u003d falcon.HTTP_406"},{"line_number":129,"context_line":"                        break"},{"line_number":130,"context_line":"                    except (common.KafkaUnavailableError, AttributeError,"},{"line_number":131,"context_line":"                            Exception):"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_bcc1f830","line":128,"updated":"2014-09-11 20:57:16.000000000","message":"Seems to me that this should be\n\n10.4.1 400 Bad Request\n\nThe request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.\n\n406 is used in this situation\n\n10.4.7 406 Not Acceptable\n\nThe resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request.\n\nUnless it was a HEAD request, the response SHOULD include an entity containing a list of available entity characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. Depending upon the format and the capabilities of the user agent, selection of the most appropriate choice MAY be performed automatically. However, this specification does not define any standard for such automatic selection.\n\n      Note: HTTP/1.1 servers are allowed to return responses which are\n      not acceptable according to the accept headers sent in the\n      request. In some cases, this may even be preferable to sending a\n      406 response. User agents are encouraged to inspect the headers of\n      an incoming response to determine if it is acceptable.\nIf the response could be unacceptable, a user agent SHOULD temporarily stop receipt of more data and query the user for a decision on further actions.\n\n\nAs this was a problem parsing the incoming JSON body that would be that the JSON is malformed.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":125,"context_line":"                        break"},{"line_number":126,"context_line":"                    except ValueError:"},{"line_number":127,"context_line":"                        LOG.exception(\u0027Message is not valid json.\u0027)"},{"line_number":128,"context_line":"                        res.status \u003d falcon.HTTP_406"},{"line_number":129,"context_line":"                        break"},{"line_number":130,"context_line":"                    except (common.KafkaUnavailableError, AttributeError,"},{"line_number":131,"context_line":"                            Exception):"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_c196d093","line":128,"in_reply_to":"fa98f980_bcc1f830","updated":"2014-09-11 21:31:36.000000000","message":"not valid json is not acceptable by this service. I am ok to change it to 400.\nI think that 406 is better.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"f2caa2a35a0fcb80106984e827ac29cc73abc7ca","unresolved":false,"context_lines":[{"line_number":132,"context_line":"                        LOG.exception(\u0027Error occurred while posting data to \u0027"},{"line_number":133,"context_line":"                                      \u0027Kafka.\u0027)"},{"line_number":134,"context_line":"                        res.status \u003d falcon.HTTP_503"},{"line_number":135,"context_line":"                        time.sleep(0.1)"},{"line_number":136,"context_line":"                        self._init_kafka()"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_9c3d142e","line":135,"updated":"2014-09-11 20:57:16.000000000","message":"Do we really want to sleep in the case that Kafka is unavailable or just return to the client a 500 or 503 error?","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"5e0ac963900f9ea2edde40a46c698badd868cf0e","unresolved":false,"context_lines":[{"line_number":132,"context_line":"                        LOG.exception(\u0027Error occurred while posting data to \u0027"},{"line_number":133,"context_line":"                                      \u0027Kafka.\u0027)"},{"line_number":134,"context_line":"                        res.status \u003d falcon.HTTP_503"},{"line_number":135,"context_line":"                        time.sleep(0.1)"},{"line_number":136,"context_line":"                        self._init_kafka()"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_5557d3c9","line":135,"updated":"2014-09-13 13:04:19.000000000","message":"Great! Look forward to the improvements.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2419,"name":"Roland Hochmuth","email":"roland.hochmuth@hpe.com","username":"roland-hochmuth-s"},"change_message_id":"d2038b494093342f1c66fb58fa6dec15684f9008","unresolved":false,"context_lines":[{"line_number":132,"context_line":"                        LOG.exception(\u0027Error occurred while posting data to \u0027"},{"line_number":133,"context_line":"                                      \u0027Kafka.\u0027)"},{"line_number":134,"context_line":"                        res.status \u003d falcon.HTTP_503"},{"line_number":135,"context_line":"                        time.sleep(0.1)"},{"line_number":136,"context_line":"                        self._init_kafka()"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_fd3efeb6","line":135,"updated":"2014-09-12 17:42:51.000000000","message":"OK. I understand. I still think this sort of logic deserves to be implemented in interface/class/method similar to what I\u0027ve out-lined above and shouldn\u0027t be repeated for every single http resource method that we are implementing.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"46c621a6e99c7033873cc6b57ba86022c8104d4f","unresolved":false,"context_lines":[{"line_number":132,"context_line":"                        LOG.exception(\u0027Error occurred while posting data to \u0027"},{"line_number":133,"context_line":"                                      \u0027Kafka.\u0027)"},{"line_number":134,"context_line":"                        res.status \u003d falcon.HTTP_503"},{"line_number":135,"context_line":"                        time.sleep(0.1)"},{"line_number":136,"context_line":"                        self._init_kafka()"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_81f048fe","line":135,"in_reply_to":"fa98f980_9c3d142e","updated":"2014-09-11 21:31:36.000000000","message":"remember the retries. want to sleep a bit then retry. Unless we do not do\nretry.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"b6ffe5ea7e617503b1568e9eef96abf649ff09b4","unresolved":false,"context_lines":[{"line_number":132,"context_line":"                        LOG.exception(\u0027Error occurred while posting data to \u0027"},{"line_number":133,"context_line":"                                      \u0027Kafka.\u0027)"},{"line_number":134,"context_line":"                        res.status \u003d falcon.HTTP_503"},{"line_number":135,"context_line":"                        time.sleep(0.1)"},{"line_number":136,"context_line":"                        self._init_kafka()"}],"source_content_type":"text/x-python","patch_set":1,"id":"fa98f980_4059da33","line":135,"in_reply_to":"fa98f980_fd3efeb6","updated":"2014-09-12 20:20:31.000000000","message":"I actually made quite a bit of changes and have a kafka_connection class\nwhich will deal with all the error conditions. Stay tuned.","commit_id":"abaf9e2b2c41a167b79388aa3c4f482f81ae7887"}],"setup.cfg":[{"author":{"_account_id":12133,"name":"Cindy O\u0027Neill","email":"cindy.o-neill@hpe.com","username":"oneilcin"},"change_message_id":"d5626806988e21aec98c2c15c5dfb0d5370875f4","unresolved":false,"context_lines":[{"line_number":22,"context_line":""},{"line_number":23,"context_line":"[files]"},{"line_number":24,"context_line":"packages \u003d"},{"line_number":25,"context_line":"    monasca"},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"data_files \u003d"},{"line_number":28,"context_line":"    /etc/monasca \u003d"}],"source_content_type":"text/x-ttcn-cfg","patch_set":5,"id":"fa98f980_ec6e202e","line":25,"updated":"2014-09-15 18:02:18.000000000","message":"The package name, and top level directory in this project, should be \"monasca_api\", not \"monasca\".  This should be installed as monasca_api.\nThis is a similar naming convention to our other components which are all installed in different packages.","commit_id":"ed99a4edb39e29a2bf1c165ee4e944a543bc597b"},{"author":{"_account_id":12133,"name":"Cindy O\u0027Neill","email":"cindy.o-neill@hpe.com","username":"oneilcin"},"change_message_id":"905cfb588df895d8010083a118f649b6fa24ba5f","unresolved":false,"context_lines":[{"line_number":22,"context_line":""},{"line_number":23,"context_line":"[files]"},{"line_number":24,"context_line":"packages \u003d"},{"line_number":25,"context_line":"    monasca"},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"data_files \u003d"},{"line_number":28,"context_line":"    /etc/monasca \u003d"}],"source_content_type":"text/x-ttcn-cfg","patch_set":5,"id":"fa98f980_07b7ba3a","line":25,"in_reply_to":"fa98f980_27a8411f","updated":"2014-09-15 20:13:50.000000000","message":"Our team voted to change it.  We want the package name to be \"monasca_api\"","commit_id":"ed99a4edb39e29a2bf1c165ee4e944a543bc597b"},{"author":{"_account_id":2860,"name":"litong01","email":"email4tong@yahoo.com","username":"litong01"},"change_message_id":"6e5f3823ad5591632cccd77707ac56c4f99ae03c","unresolved":false,"context_lines":[{"line_number":22,"context_line":""},{"line_number":23,"context_line":"[files]"},{"line_number":24,"context_line":"packages \u003d"},{"line_number":25,"context_line":"    monasca"},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"data_files \u003d"},{"line_number":28,"context_line":"    /etc/monasca \u003d"}],"source_content_type":"text/x-ttcn-cfg","patch_set":5,"id":"fa98f980_27a8411f","line":25,"in_reply_to":"fa98f980_ec6e202e","updated":"2014-09-15 18:36:14.000000000","message":"no. this is package names. should not be changed.","commit_id":"ed99a4edb39e29a2bf1c165ee4e944a543bc597b"}]}
