MySQL监控脚本
zabbix监控mysql时自定key用到的脚本
#!/usr/bin/env python
#-*- coding: UTF-8 -*- from __future__ import print_function
from mysql import connector
import logging,argparse,sys """
作者:蒋乐兴
时间:2017年2月下旬
目标:用于获取mysql状态信息、以此作为监控的基础
"""
#create user monitoruser@'127.0.0.1' identified by '123456';
#grant replication client on *.* to monitoruser@'127.0.0.1';
#grant super on *.* to monitoruser@'127.0.0.1'; class MonitorItem(object):
"""
所有监控项的基类
"""
def __init__(self,user='monitoruser',password='',host='127.0.0.1',port=3306):
"""初始化属性与到数据库端的连接"""
self.user=user
self.password=password
self.host=host
self.port=port
self.cnx=None
self.cursor=None
try:
config={'user':self.user,'password':self.password,'host':self.host,'port':self.port}
self.cnx=connector.connect(**config)
self.cursor=self.cnx.cursor(prepared=True)
except connector.Error as err:
"""如果连接失败就赋空值"""
self.cnx=None
self.cursor=None
sys.stderr.write(err.msg+'\n') def __str__(self):
attrs={}
attrs['user']=self.user
attrs['password']=self.password
attrs['host']=self.host
attrs['port']=self.port
return "instance of {0} {1}".format(self.__class__,attrs) def __del__(self):
"""在python 进行垃圾回收时关闭连接"""if self.cnx != None:
self.cnx.close() def get_result(self):
"""返回监控项的状态,由子类实现相应的功能"""
pass def print_result(self):
"""打印监控项的状态"""
print(self.get_result()) def action(self):
"""监控项达到阀值时可以触发的操作"""
print("末定义任何有意义的操作") #以下类用于检测MySQL数据库的正常与否
class IsAlive(MonitorItem):
"""监控MySQL数据库是否正常运行、{正常:on line,宕机:off line}"""
def get_result(self):
if self.cnx != None:
return "on line"
else:
return "off line" #以下类用于检测MySQL数据库的基本信息
class MysqlVariable(MonitorItem):
"""派生自MonitorItem类,用于所有variable 监控项的基类"""
variable_name=None
def get_result(self):
try:
if self.cursor != None:
stmt=r"""show global variables like '{0}';""".format(self.variable_name)
self.cursor.execute(stmt)
return self.cursor.fetchone()[1].decode('utf8')
except Exception as err:
sys.stderr.write(err.__str__()+'\n')
return -1 class MysqlPort(MonitorItem):
"""监控MySQL数据库监听是否正常、{正常:端口号,异常:-1}"""
def get_result(self):
if self.cnx != None:
return self.port
else:
return -1 class MysqlBasedir(MysqlVariable):
"""监控MySQL安装目录所在位置,{正常:安装目录位置,异常:-1}"""
variable_name="basedir" class MysqlDatadir(MysqlVariable):
"""监控MySQL数据目录所在位置,{正常:数据目录位置,异常:-1}"""
variable_name="datadir" class MysqlVersion(MysqlVariable):
"""监控MySQL版本号,{正常:版本号,异常:-1}"""
variable_name="version" class MysqlServerId(MysqlVariable):
"""监控MySQL的server_id"""
variable_name="server_id" class MysqlLogBin(MysqlVariable):
"""binlog 是否有开启"""
variable_name="log_bin" class MysqlLogError(MysqlVariable):
"""errorlog文件名"""
variable_name="log_error" class MysqlPerformanceSchema(MysqlVariable):
"""performance_schema是否有开启"""
variable_name="performance_schema" class MysqlInnodbBufferPoolSize(MysqlVariable):
"""监控MySQL innodb_buffer_pool的大小,{正常:缓冲池大小(byte),异常:-1}"""
variable_name="innodb_buffer_pool_size" class MysqlMaxConnections(MysqlVariable):
"""最大连接数"""
variable_name="max_connections" #派生自MonitorItem类,用于所有status 监控项的基类
class MysqlStatu(MonitorItem):
"""派生自MonitorItem类,用于所有statu 监控项的基类"""
statu_name=None
def get_result(self):
try:
if self.cursor != None:
stmt=r"""show global status like '{0}';""".format(self.statu_name)
self.cursor.execute(stmt)
return self.cursor.fetchone()[1].decode('utf8')
except Exception as err:
sys.stderr.write(err.__str__()+'\n')
return -1 class MysqlCurrentClient(MysqlStatu):
"""当前的客户端连接数"""
statu_name="Threads_connected" class MysqlTableOpenCacheHitRate(MysqlStatu):
"""表缓存命中率"""
def get_result(self):
try:
if self.cursor != None:
stmt=r"""show global status like 'table_open_cache_hits';"""
self.cursor.execute(stmt)
hit=float((self.cursor.fetchone()[1].decode('utf8')))
stmt=r"""show global status like 'table_open_cache_misses';"""
self.cursor.execute(stmt)
miss=float(self.cursor.fetchone()[1].decode('utf8'))
return hit/(hit+miss)
except Exception as err:
sys.stderr.write(err.__str__())
return -1 class MysqlTableOpenCacheOverflows(MysqlStatu):
"""表缓存溢出次数,如果大于0,可以增大table_open_cache和table_open_cache_instances."""
statu_name="Table_open_cache_overflows" class MysqlTableLocksWaited(MysqlStatu):
"""因不能立刻获得表锁而等待的次数"""
statu_name="table_locks_waited" class MysqlSlowqueries(MysqlStatu):
"""执行时间超过long_query_time的查询次数,不管慢查询日志有没有打开"""
statu_name="slow_queries" class MysqlSortScan(MysqlStatu):
"""全表扫描之后又排序(排序键不是主键)的次数"""
statu_name="sort_scan" class MysqlSortRows(MysqlStatu):
"""与sortscan差不多,前者指的是sortscan的次数,srotrows指的是sort操作影响的行数"""
statu_name="sort_rows" class MysqlSortRange(MysqlStatu):
"""根据索引进行范围扫描之后再进行排序(排序键不能是主键)的次数"""
statu_name="sort_range" class MysqlSortMergePasses(MysqlStatu):
"""排序时归并的次数,如果这个值比较大(要求高一点大于0)那么可以考虑增大sort_buffer_size的大小"""
statu_name="sort_merge_passes" class MysqlSelectRangeCheck(MysqlStatu):
"""如果这个值不是0那么就要好好的检查表上的索引了"""
statu_name="select_range_check" class MysqlQuestions(MysqlStatu):
"""erver端执行的语句数量,但是每执行一个语句它又只增加一,这点让我特别被动"""
statu_name="Questions" class MysqlQcacheFreeMemory(MysqlStatu):
"""query cache 的可用内存大小"""
statu_name="qcache_free_memory" class MysqlPreparedStmtCount(MysqlStatu):
"""由于本监控程序就是通过prepare语句完成的,所以这个监控项的值最少会是1不是0"""
statu_name="prepared_stmt_count" class MysqlOpenedTables(MysqlStatu):
"""mysql数据库打开过的表,如果这个值过大,应该适当的增大table_open_cache的值"""
statu_name="opened_tables" class MysqlOpenTables(MysqlStatu):
"""当前mysql数据库打开的表数量"""
statu_name="open_tables" class MysqlServerLevelOpenFiles(MysqlStatu):
"""mysql数据库的server层当前正打开的文件数据"""
statu_name="open_files" class MysqlInnodbAvailableUndoLogs(MysqlStatu):
"""innodb当前可用的undo段的数据"""
statu_name="innodb_available_undo_logs" class MysqlInnodbNumOpenFiles(MysqlStatu):
"""innodb当前打开的文件数量"""
statu_name="innodb_num_open_files" class MysqlInnodbRowsUpdated(MysqlStatu):
"""innodb层面执行的update所影响的行数"""
statu_name="innodb_rows_updated" class MysqlInnodbRowsRead(MysqlStatu):
"""innodb 层面受读操作所影响的行数"""
statu_name="innodb_rows_read" class MysqlInnodbRowsInserted(MysqlStatu):
"""innodb 层面受insert操作所影响的行数"""
statu_name="innodb_rows_inserted" class MysqlInnodbRowsDeleted(MysqlStatu):
"""innodb 层面受delete操作所影响的行数"""
statu_name="innodb_rows_deleted" class MysqlInnodbRowLockWaits(MysqlStatu):
"""innodb 行锁等待的次数"""
statu_name="innodb_row_lock_waits" class MysqlInnodbRowLockTimeMax(MysqlStatu):
"""innodb层面行锁等待的最大毫秒数"""
statu_name="innodb_row_lock_time_max" class MysqlInnodbRowLockTimeAvg(MysqlStatu):
"""innodb层面行锁等待的平均毫秒数"""
statu_name="Innodb_row_lock_time_avg" class MysqlInnodbRowLockTime(MysqlStatu):
"""innodb层面行锁等待的总毫秒数"""
statu_name="Innodb_row_lock_time" class MysqlInnodbPagesWritten(MysqlStatu):
"""innodb层面写入磁盘的页面数"""
statu_name="Innodb_pages_written" class MysqlInnodbPagesRead(MysqlStatu):
"""从innodb buffer pool 中读取的页数"""
statu_name="Innodb_pages_read" class MysqlInnodbOsLogWritten(MysqlStatu):
"""innodb redo 写入字节数"""
statu_name="Innodb_os_log_written" class MysqlInnodbOsLogPendingWrites(MysqlStatu):
"""innodb redo log 被挂起的写操作次数"""
statu_name="Innodb_os_log_pending_writes" class MysqlInnodbOsLogPendingFsyncs(MysqlStatu):
"""innodb redo log 被挂起的fsync操作次数"""
statu_name="Innodb_os_log_pending_fsyncs" class MysqlInnodbOsLogFsyncs(MysqlStatu):
"""innodb redo log fsync的次数"""
statu_name="Innodb_os_log_fsyncs" class MysqlInnodbLogWrites(MysqlStatu):
"""innodb redo log 物理写的次数"""
statu_name="innodb_log_writes" class MysqlInnodbLogWriteRequests(MysqlStatu):
"""innodb redo log 逻辑写的次数"""
statu_name="Innodb_log_write_requests" class MysqlInnodbLogWaits(MysqlStatu):
"""innodb 写redo 之前必须等待的次数"""
statu_name="Innodb_log_waits" class MysqlInnodbDblwrWrites(MysqlStatu):
"""innodb double write 的次数"""
statu_name="Innodb_dblwr_writes" class MysqlInnodbDblwrPagesWritten(MysqlStatu):
"""innodb double write 的页面数量"""
statu_name="Innodb_dblwr_pages_written" class MysqlInnodbDoubleWriteLoader(MysqlStatu):
"""innodb double write 压力1~64、数值越大压力越大"""
def get_result(self):
try:
if self.cursor != None:
stmt=r"""show global status like 'innodb_dblwr_pages_written';"""
self.cursor.execute(stmt)
pages=float((self.cursor.fetchone()[1].decode('utf8')))
stmt=r"""show global status like 'innodb_dblwr_writes';"""
self.cursor.execute(stmt)
requests=float(self.cursor.fetchone()[1].decode('utf8'))
if requests == 0:
return 0
return pages/requests
except Exception as err:
sys.stderr.write(err.__str__())
return -1 class MysqlInnodbBufferPoolHitRate(MysqlStatu):
"""innodb buffer pool 命中率"""
def get_result(self):
try:
if self.cursor != None:
stmt=r"""show global status like 'innodb_buffer_pool_read_requests';"""
self.cursor.execute(stmt)
hit_read=float((self.cursor.fetchone()[1].decode('utf8')))
stmt=r"""show global status like 'innodb_buffer_pool_reads';"""
self.cursor.execute(stmt)
miss_read=float(self.cursor.fetchone()[1].decode('utf8'))
total_read=(miss_read+hit_read)
if total_read == 0:
return 0
return hit_read/total_read
except Exception as err:
sys.stderr.write(err.__str__())
return -1 class MysqlInnodbBufferPoolFreePagePercent(MysqlStatu):
"""innodb buffer pool free page 百分比"""
def get_result(self):
try:
if self.cursor != None:
stmt=r"""show global status like 'innodb_buffer_pool_pages_total';"""
self.cursor.execute(stmt)
total_page=float((self.cursor.fetchone()[1].decode('utf8')))
stmt=r"""show global status like 'innodb_buffer_pool_pages_free';"""
self.cursor.execute(stmt)
free_page=float(self.cursor.fetchone()[1].decode('utf8'))
return free_page/total_page
except Exception as err:
sys.stderr.write(err.__str__())
return -1 class MysqlInnodbBufferPoolDirtyPercent(MysqlStatu):
"""innodb buffer pool dirty page 百分比"""
def get_result(self):
try:
if self.cursor != None:
stmt=r"""show global status like 'innodb_buffer_pool_pages_total';"""
self.cursor.execute(stmt)
total_page=float((self.cursor.fetchone()[1].decode('utf8')))
stmt=r"""show global status like 'innodb_buffer_pool_pages_dirty';"""
self.cursor.execute(stmt)
dirty_page=float(self.cursor.fetchone()[1].decode('utf8'))
return dirty_page/total_page
except Exception as err:
sys.stderr.write(err.__str__())
return -1 class MysqlCreated_tmp_disk_tables(MysqlStatu):
"""mysql运行时所创建的磁盘临时表的数量,如果这个数值比较大,可以适当的增大 tmp_table_size | max_heap_table_size"""
statu_name="Created_tmp_disk_tables" class MysqlComSelect(MysqlStatu):
"""select 语句执行的次数"""
statu_name="com_select" class MysqlComInsert(MysqlStatu):
"""insert 语句执行的次数"""
statu_name="com_insert" class MysqlComDelete(MysqlStatu):
"""delete 语句执行的次数"""
statu_name="com_delete" class MysqlComUpdate(MysqlStatu):
"""update 语句执行的次数"""
statu_name="com_update" class MysqlBinlogCacheDiskUse(MysqlStatu):
"""事务引擎因binlog缓存不足而用到临时文件的次数,如果这个值过大,可以通过增大binlog_cache_size来解决"""
statu_name="Binlog_cache_disk_use" class MysqlBinlogStmtCacheDiskUse(MysqlStatu):
"""非事务引擎因binlog缓存不足而用到临时文件的次数,如果这个值过大,可以通过增大binlog_stmt_cache_size来解决"""
statu_name="Binlog_stmt_cache_disk_use" class MysqlReplication(MonitorItem):
"""所有监控mysql replication的基类"""
def __init__(self,user='monitoruser',password='',host='127.0.0.1',port=3306):
MonitorItem.__init__(self,user,password,host,port)
try:
if self.cursor != None:
stmt="show slave status;"
self.cursor.execute(stmt)
self.replication_info=self.cursor.fetchone()
except Exception as err:
pass class MysqlReplicationIsRunning(MysqlReplication):
"""mysql replication 是否正常运行"""
def get_result(self):
if self.replication_info == None:
return "replication is not running"
else:
slave_io_running=self.replication_info[10].decode('utf8')
slave_sql_running=self.replication_info[11].decode('utf8')
if slave_io_running == 'Yes' and slave_sql_running == 'Yes':
return "running"
return "replication is not running" class MysqlReplicationBehindMaster(MysqlReplication):
"""监控seconde behind master """
def get_result(self):
if self.replication_info != None:
return self.replication_info[32]
else:
return -1 #监控项字典
items={
#实例配置信息收集项
'port' :MysqlPort,
'baseDir' :MysqlBasedir,
'dataDir' :MysqlDatadir,
'version' :MysqlVersion,
'serverId' :MysqlServerId,
'isBinlogEnable' :MysqlLogBin,
'isErrorlogEnable' :MysqlLogError,
'isPerformanceScheamEnable' :MysqlPerformanceSchema,
'innodbBufferPoolSize' :MysqlInnodbBufferPoolSize,
'maxConnections' :MysqlMaxConnections, #实例运行时信息收集项
'isOnLine' :IsAlive,
'currentConnections' :MysqlCurrentClient,
'tableCacheHitRate' :MysqlTableOpenCacheHitRate,
'tableOpenCacheOverflows' :MysqlTableOpenCacheOverflows,
'tableLocksWaited' :MysqlTableLocksWaited,
'slowqueries' :MysqlSlowqueries,
'sortScan' :MysqlSortScan,
'sortRows' :MysqlSortRows,
'sortRange' :MysqlSortRange,
'sortMergePasses' :MysqlSortMergePasses,
'selectRangeCheck' :MysqlSelectRangeCheck,
'questions' :MysqlQuestions,
'qcacheFreeMemory' :MysqlQcacheFreeMemory,
'preparedStmtCount' :MysqlPreparedStmtCount,
'openedTables' :MysqlOpenedTables,
'openTables' :MysqlOpenTables,
'serverLevelOpenFiles' :MysqlServerLevelOpenFiles,
'created_tmp_disk_tables' :MysqlCreated_tmp_disk_tables,
'comSelect' :MysqlComSelect,
'comInsert' :MysqlComInsert,
'comDelete' :MysqlComDelete,
'comUpdate' :MysqlComUpdate,
'binlogCacheDiskUse' :MysqlBinlogCacheDiskUse,
'binlogStmtCacheDiskUse' :MysqlBinlogStmtCacheDiskUse, #innodb运行时信息收集项
'innodbAvailableUndoLogs' :MysqlInnodbAvailableUndoLogs,
'innodbOpenFiles' :MysqlInnodbNumOpenFiles,
'innodbRowsUpdated' :MysqlInnodbRowsUpdated,
'innodbRowsRead' :MysqlInnodbRowsRead,
'innodbRowsInserted' :MysqlInnodbRowsInserted,
'innodbRowsDeleted' :MysqlInnodbRowsDeleted,
'innodbRowLockWaits' :MysqlInnodbRowLockWaits,
'innodbRowLockTimeMax' :MysqlInnodbRowLockTimeMax,
'innodbRowLockTimeAvg' :MysqlInnodbRowLockTimeAvg,
'innodbRowLockTime' :MysqlInnodbRowLockTime,
'innodbPagesWritten' :MysqlInnodbPagesWritten,
'innodbPagesRead' :MysqlInnodbPagesRead,
'innodbOsLogWritten' :MysqlInnodbOsLogWritten,
'innodbOsLogPendingWrites' :MysqlInnodbOsLogPendingWrites,
'innodbOsLogPendingFsyncs' :MysqlInnodbOsLogPendingFsyncs,
'innodbOsLogFsyncs' :MysqlInnodbOsLogFsyncs,
'innodbLogWrites' :MysqlInnodbLogWrites,
'innodbLogWriteRequests' :MysqlInnodbLogWriteRequests,
'innodbLogWaits' :MysqlInnodbLogWaits,
'innodbDblwrWrites' :MysqlInnodbDblwrWrites,
'innodbDblwrPagesWritten' :MysqlInnodbDblwrPagesWritten,
'innodbDoubleWriteLoader' :MysqlInnodbDoubleWriteLoader,
'innodbBufferPoolHitRate' :MysqlInnodbBufferPoolHitRate,
'innodbBufferPoolFreePagePercent' :MysqlInnodbBufferPoolFreePagePercent,
'innodbBufferPoolDirtyPercent' :MysqlInnodbBufferPoolDirtyPercent, #对mysql replication 的监控
'replicationIsRunning' :MysqlReplicationIsRunning,
'replicationBehindMaster' :MysqlReplicationBehindMaster,
} #
item_key_names=[name for name in items.keys()] if __name__=="__main__":
parser=argparse.ArgumentParser()
parser.add_argument('--user',default='monitoruser',help='user name for connect to mysql')
parser.add_argument('--password',default='',help='user password for connect to mysql')
parser.add_argument('--host',default='127.0.0.1',help='mysql host ip')
parser.add_argument('--port',default=3306,type=int,help='mysql port')
parser.add_argument('monitor_item_name',choices=item_key_names)
args=parser.parse_args()
m=items[args.monitor_item_name](host=args.host,port=args.port,user=args.user,password=args.password)
m.print_result()
MySQL监控脚本的更多相关文章
- Zabbix Windos mysql 监控脚本
说明:判断mysql主进程是否关闭,如果关闭则返回0 创建文件:MySQL-ping.vbs Set objFS = CreateObject("Scripting.FileSystemOb ...
- Mysql 监控脚本
cat mysql_status_output.py #coding=utf-8import jaydebeapiimport sysimport pymysqlimport osfrom prome ...
- 关于mysql和Apache以及nginx的监控脚本怎么写会比较好的记录
最近,自己业务进行上线,上线后,需要考虑的是对各种服务进行监控,包括(httpd服务,mysqld服务等),现在想以mysqld服务为例总结下那种方式的脚本最为专业和合理: (1).根据mysql的端 ...
- MySQL慢日志监控脚本实例剖析
公司线上的 MySQL 慢日志,之前一直没有做好监控.趁着上周空闲,我就把监控脚本写了下,今天特地把代码发出来与51博友分享一下. 针对脚本的注解和整体构思,我会放到脚本之后为大家详解. 1 2 3 ...
- centos shell编程6一些工作中实践脚本 nagios监控脚本 自定义zabbix脚本 mysql备份脚本 zabbix错误日志 直接送给bc做计算 gzip innobackupex/Xtrabackup 第四十节课
centos shell编程6一些工作中实践脚本 nagios监控脚本 自定义zabbix脚本 mysql备份脚本 zabbix错误日志 直接送给bc做计算 gzip innobacku ...
- centos 7中监控mysql 数据库脚本(监控端口)
centos 7中监控mysql 数据库脚本(监控端口) 监控mysql数据库的方法如下: 1.监控端口 netstat -nltp |grep 3306 2.监控进程 ps -ef |grep 33 ...
- MySQL的keepalived高可用监控脚本
MySQL的keepalived高可用监控脚本 MySQL(或者其它服务)的keepalived高可用监控脚本 开发脚本需求 :我们知道,keepalive是基于虚拟ip的存活来判断是否抢占maste ...
- shell监控脚本实例—监控mysql主从复制
分享一例shell脚本,用于监测mysql数据库的主从复制,有需要的朋友不妨参考学习下. 转自:http://www.jbxue.com/article/14103.html(转载请注明出处) 本节内 ...
- my34_脚本冥等添加自动任务-mysql监控部署
场景: 定义一套添加mysql监控的脚本,在mysql安装完毕后,一键执行添加监控 已有以下的等一系列命令可以读取mysql从库的延迟时间并推向influxdb,变化的部分为 -P 端口.-k k ...
随机推荐
- CentOS通过日志反查入侵(转)
1.查看日志文件 Linux查看/var/log/wtmp文件查看可疑IP登陆 last -f /var/log/wtmp 该日志文件永久记录每个用户登录.注销及系统的启动.停机的事件.因此随着系统 ...
- mysql mapper 大于小于号 tag name expected
xml文件的某些特殊字符是自动转义的, 我们不希望它被转义,可以用<![CDATA[]]>, xml解析器会忽视CDATA中的内容, 比如:<![CDATA[<]]> 或 ...
- simple_strtoul()
//此函数有以下几点值得注意: //1.第一个参数中的const.一般在函数的形参中,如果我们只是希望调用者使用该参数,而不会去改变该参数 // 内容(一般是指针指向的内容),则可以声明为co ...
- golang解析json格式 -- 全
项目中客户端和服务端的交互数据部分为json,因此在服务端就得解析,复杂的json解析起来其实还是挺费劲的. 交互的数据类似如下格式: {"sn":1,"ls" ...
- LESS,强大的CSS预处理语言
虽然写的css不多,但是我已经切身感觉到了书写css的恶心...抛开最令人烦的浏览器兼容问题不说,这个语言本身就有不少问题. 最简单的,比如多个地方是同一个颜色的,如果可以写在一个样式里还没什么,但是 ...
- SaltStack–Job管理
官方文档:https://docs.saltstack.com/en/2016.11/ref/modules/all/salt.modules.saltutil.html 在SaltStack里面执行 ...
- linux 调度总结(转载)
调度: 操作系统的调度程序的两项任务: 1: 调度: 实现调度策略,决定就绪的进程.线程竞争cpu的次序的裁决原则.说白了就是进程和线程何时应该放弃cpu和选择那个就绪进程.线程来执行. 2: 分派: ...
- Python自然语言处理资料库
1.LTP [1]- 语言技术平台(LTP) 提供包括中文分词.词性标注.命名实体识别.依存句法分析.语义角色标注等丰富. 高效.精准的自然语言处理技术.经过哈工大社会计算与信息检索研究中心 11 年 ...
- 构建高可用Linux服务器二
centos优化: 1.关闭不需要的服务:ntsysv crond:自动计划任务 network:已配置网络接口的脚步程序服务. sshd:openssh服务器守护进程. irqbalance:启用i ...
- 用java源代码学数据结构<七>: BST
/* * 以int类为例 * 其它的类必须能够比较 * */ //二叉搜索树的节点点 class BSTNode{ int item; BSTNode lc; BSTNode rc; BSTNode ...