# -*- coding: utf-8 -*- # Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sqlalchemy as sa import hashlib from datetime import datetime, timedelta from appenlight.models import Base from sqlalchemy.dialects.postgresql import JSON from ziggurat_foundations.models.base import BaseModel class SlowCall(Base, BaseModel): __tablename__ = "slow_calls" __table_args__ = {"implicit_returning": False} resource_id = sa.Column(sa.Integer(), nullable=False, index=True) id = sa.Column(sa.Integer, nullable=False, primary_key=True) report_id = sa.Column( sa.BigInteger, sa.ForeignKey("reports.id", ondelete="cascade", onupdate="cascade"), primary_key=True, ) duration = sa.Column(sa.Float(), default=0) statement = sa.Column(sa.UnicodeText(), default="") statement_hash = sa.Column(sa.Unicode(60), default="") parameters = sa.Column(JSON(), nullable=False, default=dict) type = sa.Column(sa.Unicode(16), default="") subtype = sa.Column(sa.Unicode(16), default=None) location = sa.Column(sa.Unicode(255), default="") timestamp = sa.Column( sa.DateTime(), default=datetime.utcnow, server_default=sa.func.now() ) report_group_time = sa.Column( sa.DateTime(), default=datetime.utcnow, server_default=sa.func.now() ) def set_data( self, data, protocol_version=None, resource_id=None, report_group=None ): self.resource_id = resource_id if data.get("start") and data.get("end"): self.timestamp = data.get("start") d = data.get("end") - data.get("start") self.duration = d.total_seconds() self.statement = data.get("statement", "") self.type = data.get("type", "unknown")[:16] self.parameters = data.get("parameters", {}) self.location = data.get("location", "")[:255] self.report_group_time = report_group.first_timestamp if "subtype" in data: self.subtype = data.get("subtype", "unknown")[:16] if self.type == "tmpl": self.set_hash("{} {}".format(self.statement, self.parameters)) else: self.set_hash() def set_hash(self, custom_statement=None): statement = custom_statement or self.statement self.statement_hash = hashlib.sha1(statement.encode("utf8")).hexdigest() @property def end_time(self): if self.duration and self.timestamp: return self.timestamp + timedelta(seconds=self.duration) return None def get_dict(self): instance_dict = super(SlowCall, self).get_dict() instance_dict["children"] = [] instance_dict["end_time"] = self.end_time return instance_dict def es_doc(self): doc = { "resource_id": self.resource_id, "timestamp": self.timestamp, "pg_id": str(self.id), "permanent": False, "request_id": None, "log_level": "UNKNOWN", "message": self.statement, "namespace": "appenlight.slow_call", "tags": { "report_id": { "values": self.report_id, "numeric_values": self.report_id, }, "duration": {"values": None, "numeric_values": self.duration}, "statement_hash": { "values": self.statement_hash, "numeric_values": None, }, "type": {"values": self.type, "numeric_values": None}, "subtype": {"values": self.subtype, "numeric_values": None}, "location": {"values": self.location, "numeric_values": None}, "parameters": {"values": None, "numeric_values": None}, }, "tag_list": [ "report_id", "duration", "statement_hash", "type", "subtype", "location", ], } if isinstance(self.parameters, str): doc["tags"]["parameters"]["values"] = self.parameters[:255] return doc @property def partition_id(self): return "rcae_sc_%s" % self.report_group_time.strftime("%Y_%m")