Ansible-Playbook
目录
1、概念介绍
roles 角色
playbook 核心元素
ansible-playbook 命令
playbook 简单案例
2、Ansible 变量
自定义变量
facts 变量
Palybook 部署 LAMP
ansible 端安装 LAMP
playbook 系统环境脚本
构建 httpd 任务
构建 mariadb 任务
构建 php 任务
编写整个任务入口文件
1、概念介绍
Ansible Playbooks 提供了一个可重复、可重用、简单的配置管理和多机部署系统,非常适合部署复杂的应用程序。当你需要反复执行或要执行多个 task 时,可以将这些 task 编写入 playbook,然后用 playbook 推送给在 inventory 中定义好的一组服务器执行。
playbook 以 YAML 格式表示。一个 playbook 由一个或多个 play 组成,一个 play 中
包含一个或多个 task,一个 task 对应一个 module。 playbook 按从上到下的顺序运行。在每个 play 中,tasks 也按从上到下的顺序运行。
roles 角色
当我们刚开始学习运用 playbook 时,因为操作很多,所以很可能会把 playbook 写成一个很大的文件,慢慢你会发现,playbook 的内容较为混乱,难以管理。Roles 相当于我们剧本当中的角色,把不同的任务分配给不同的角色,可以使大型项目易管理,当需要做不同的事情时,只需要调用不同角色即可。
把不同功能的 playbook 分开,一个标准的角色含有下列子目录:
角色子目录 | 说明 |
defaults | 其中的 main.yml 包含角色变量的默认值,在所有变量中优先级最低 |
files | 包含角色任务引用的静态文件 |
handlers | 主要定义处理程序 |
meta | 角色相关信息,如作者、许可证等 |
tasks | 定义任务 |
templates | 任务引用的 jinja2 模板 |
tests | 可以包含清单和 test.yml 的 playbook,用于测试 |
vars | 定义角色的变量 |
playbook 核心元素
① target:定义 PlayBook 的远程主机组
target 常用参数 | 说明 |
hosts | 运行指定任务的目标主机,可以是一个主机组、主机、多个主机,中间以冒号分隔,也可以用 all 参数表示所有主机。 |
remote_user | 指定远程主机上的执行任务的用户。 |
gather_facks | 获取远程主机 facts 基础信息。注:gather_facts: True 表示在远程主机运行 setup 模块,获取远程主机的 facts,facts 就是变量,内建变量 。每个主机的各种信息,cpu 颗数、内存大小等,会存在 facts 中的某个变量中,调用后返回很多对应主机的信息。 |
② variables:定义 PlayBook 使用的变量
variables 常用参数 | 说明 |
vars | 在 yaml 文件中定义变量赋值。定义格式,变量名:变量值 |
vars_files | 指定变量文件,在文件中定义变量 |
③ tasks:定义远程主机上执行的任务列表
tasks 常用参数 | 说明 |
name | 任务显示名称也是屏幕显示信息 |
module_name | module_args: 需要使用的模块名字: 模块参数 |
关于 task 说明:
- Play 的主体部分是 task 列表,task 列表中的各任务按次序逐个在 hosts 中指定的主机上执行
- 在运行 playbook 时(从上到下执行),如果一个 host 执行 task 失败,整个 tasks都会回滚,请修正 playbook 中的错误,然后重新执行即可。
- 每一个 task 必须有一个名称 name,这样在运行 playbook 时,从其输出的任务执行信息中可以很好的辨别出是属于哪一个 task 的。
- 定义一个 task,常见的格式:” module_name: module_args” 例如:yum: name=httpd state=absent update_cache=yes
- ansible 的自带模块中,command 模块和 shell 模块无需使用 key=value 格式
④ handlers:处理器,当某条件满足时,触发执行的操作。例如修改配置文件之后,启动跟 handlers 任务重启相关联的服务 。
handler 常用参数 | 说明 |
notify | notify”这个 action 可用于在每个 play 的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性地执行指定操作。 在 notify 中列出的操作称为 handler,也即 notify 中调用 handler 中定义的操作。 |
handler | 也是 task 的列表。在 notify 中列出的操作称为 handler,也即 notify 中 调用 handler 中定义的操作。 Handlers 是由通知者进行 notify, 如果没有被 notify,handlers 不会执行。 不管有多少个通知者进行了 notify,等到 play 中的所有 task 执行完成之后,handlers 也只会被执行一次。 |
⑤ roles :角色,用于层次性、结构化地组织 playbook。roles 能够根据层次型结构自动装载变量文件、tasks 以及 handlers 等。
ansible-playbook 命令
语法:ansible [选项] yaml文件
- -C, --check 只检测可能会发生的改变,但不真执行操作
- -D, --diff 更改(小)文件和模板时,显示这些文件中的差异
- --list-hosts 输出匹配主机的列表;不执行任何其他操作
- --list-tasks 列出将要执行的所有任务
- --syntax-check 对 playbook 执行语法检查,但不要执行
- -t TAGS_NAME 表示跳过标签前的步骤,直接从标签位置开始
ansible-playbook --syntax-check install.yaml
playbook 简单案例
github 上提供了大量的实例供大家参考: https://github.com/ansible/ansible-examples
vim install.yaml
---
- name: yum install packagehosts: web_serversremote_user: rootvars:name1: treetasks:- name: install lrzszcommand: yum install -y lrzsz- name: install treecommand: yum install -y {{name1}}
第一行:使用三个横杠作为开始,在 YAML 语法中,---表示文档开始。
第二行:使用- 开头(横杠后面有空格),YAML 使用"-"表示一个块序列的节点,name play 的名称
第三行:hosts 关键字对应的值为 web-servers,表示我们要在 web-servers 主机组上进行操作
第四行:使用 remote_user 关键字可以指定在进行远程操作时使用哪个用户进行操作,'remote_user: root'表示以远程主机的 root 用户进行操作, 与 hosts 关键字对齐,表示它们是平级的
第五行:vars 设置变量,格式为 key:values
第七行:tasks 任务列表,整个任务列表一共有两个任务组成,每个任务都以"- "开头,每个任务都有自己的名字,任务名使用 name 关键字进行指定,name 下是 我们执行任务的模块。变量调用使{{var}}
# 执行 playbook
ansible-playbook install.yaml
注意:Gathering Facts 任务会收集当前 play 对应的目标主机的相关信息,收集完这些基础信息后,才会执行我们指定的任务。
2、Ansible 变量
自定义变量
① 在剧本中定义变量
---
- hosts: webvars:file: /etc/hostnamedir: /roottasks:- name: print vardebug:msg: "{{ dir }}变量file的内容是{{ file }}"
注意:如果msg起始位置有变量需要使用引号。
② 在文件中定义变量
# vars-file.yml
file: /etc/hostname
dir: /root
---
- hosts: webvars_files: ./vars-file.ymltasks:- name: print vardebug:msg: "{{ dir }}变量file的内容是{{ file }}"
③ 根据主机清单分组自动识别变量
通过主机清单里面的分组进行变量的共享,eg:web服务器 port 80,data服务器 port 873
group_vars/lb/vars.yml # 存放lb组的变量web/vars.yml # 存放web组的变量data/vars.yml # 存xxx组的变量all/vars.yml # 存放所有主机共用的变量mkdir -p /etc/ansible/lamp/group_vars
cd /etc/ansible/lamp/group_vars
mkdir {lb, web, data, all}vim data_vars.yml
port: 873vim web_vars.yml
port: 80
---
- hosts: webtasks:- name: print vardebug:msg: "当前服务的端口号:{{ port }}"- hosts: datatasks:- name: print vardebug:msg: "当前服务的端口号:{{ port }}"
facts 变量
fact变量是在运行剧本的时候ansible收集的每台机器的信息
# 查看ansible facts 变量
ansible web_servers -m setup
# 编写剧本
---
- hosts:tasks: print facts vars- name: print facts varsdebug:msg: "facts变量{{ ansible_default_ipv4.addresses }}"
常用 facts 变量
- ansible_hostname 主机名
- ansible_memtotal_mb 内存大小(总计),单位mb
- ansible_processor_vcpus cpu数量
在 /etc/motd 写入主机名,ip地址,内存大小,cpu个数
#批量分发 motd 文件,文件内容根据不容机器变化
①②③④⑤
Palybook 部署 LAMP
ansible 端安装 LAMP
首先,我们可以在 ansible 服务器上安装 LAMP 环境,然后,再将配置文件通过 ansible 拷贝到远程主机上,如果有配置文件不用在管理机安装 LAMP。
① 安装软件
# ---------------------------------安装 httpd---------------------------------
yum install -y httpd
systemctl start httpd#------------------------------------ 安装 MySQL ----------------------------
yum install -y mariadb-server mariadb
# 创建数据库保存目录
mkdir -p /data/mysql/data
# 修改权限
chown -R mysql:mysql /data/mysql/
# 修改数据保存目录
vim /etc/my.cnf
datadir=/data/mysql/data# 启动服务
systemctl start mariadb# --------------------------安装 PHP 和 php-mysql 模块 --------------------------------
yum install -y php php-mysql
# 提供 php 的测试页
vim /var/www/html/index.php
<?php phpinfo();
?>
# 重启httpd 服务
systemctl restart httpd
确保已经出现上面的测试页,而且,要看到 MySQL 已经被整合进来了,才能进行下一步操作
② 配置主机 和 ssh登录
# 定义主机名
vim /etc/ansible/hosts
[web-servers]
192.168.137.105
192.168.137.106# 设置 ssh 免密连接
ssh-keygen
ssh-copy-id root@192.168.137.105
ssh-copy-id root@192.168.137.106
playbook 系统环境脚本
# 创建相关文件
mkdir -pv /etc/ansible/lamp/roles/{prepare,httpd,mysql,php}/{tasks,files,templates,vars,meta,default,handlers}# 拷贝文件:将搭建成功的 LAMP 环境的 httpd 和 MySQL 的配置文件拷贝到对应目录下
cp /etc/httpd/conf/httpd.conf lamp/roles/httpd/files/
cp /etc/my.cnf lamp/roles/mysql/files/#初始化系统环境的脚本:写 prepare(上面创建好的)角色的 playbooks
vim lamp/roles/prepare/tasks/main.yml
- name: delete yum config shell: rm -rf /etc/yum.repos.d/* #删除原有的 yum 配置文件
- name: provide yumrepo file get_url: url: http://mirrors.aliyun.com/repo/Centos-6.repo dest: /etc/yum.repos.d/CentOS-Base.repo when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6")
- name: provide yumrepo file get_url: url: http://mirrors.aliyun.com/repo/Centos-7.repo dest: /etc/yum.repos.d/CentOS-Base.repo when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "7")
- name: clean the yum repo shell: yum clean all #清除原有的 yum 缓存信息
- name: clean the iptables shell: iptables -F #清除原有防火墙规则,不然后可能上不了网
- name: close firewalld service: name=firewalld state=stopped enabled=no
- name: close selinux template: src: config.j2 dest: /etc/selinux/config
- name: current close selinux command: setenforce 0 ignore_errors: true
[root@node_04 ansible] cp /etc/selinux/config lamp/roles/prepare/templates/config.j2
template 模块跟 copy 模块类似,指定模版文件,该文件必须存在于 prepare 角色目录下的 templates 目录中,起名需要加上.j2 结尾,将 templates 下的文件复制到对应主机的对应目录下,src 指定源文件,dest 指定目标目录及复制到目录后改成什么名字。
该模块和 copy 模块作用基本一样,都是把某个文件复制到远端主机上,但是区别在于 template 模块可以获取变量的值,而 copy 则是原封不动的把文件内容复制过去。
构建 httpd 任务
① 配置 httpd 的 tasks
cd /etc/ansible/lamp/roles
cp /var/www/html/index.php httpd/files/
vim httpd/tasks/main.yml
---
- name: web server install yum: name=httpd state=present - name: provide test page # 提供测试页copy: src=index.php dest=/var/www/html- name: delete apache config # 删除原有的 apache 配置文件,如果不删除,下面的 copy 任务是不会执行的,# 因为当源文件 httpd.conf 和目标文件一样时,copy 命令是不执行的。# 如果 copy 命令不执行,那么 notify 将不调用 handler。shell: rm -rf /etc/httpd/conf/httpd.conf - name: provide configuration file # 提供 httpd 的配置文件copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf # 当前面的 copy 复制成功后,通过 notify 通知名字为 restart httpd 的 handlers 运行。notify: restart httpd
② 构建 httpd 的 handlers
vim httpd/handlers/main.yml
- name: restart httpd service: name=httpd enabled=yes state=restarted
构建 mariadb 任务
创建 MySQL 服务的任务,需要安装 MySQL 服务,改变属主信息,启动 MySQL
vim /etc/ansible/lamp/roles/mysql/tasks/main.yml
---# 安装 mysql 服务
- name: install the mysql yum: name: ['mariadb-server', 'mariadb','MySQL-python'] state: present # 创建数据挂载点目录
- name: mkdir data directory shell: mkdir -p /data/mysql/data# 提供 mysql 的配置文件
- name: provide configration file copy: src=my.cnf dest=/etc/my.cnf # 更改属主和属组
- name: chage the owner shell: chown -R mysql:mysql /data/mysql# 启动 mysql 服务
- name: start mariadb service: name=mariadb enabled=yes state=started- name: set root passwd shell: /usr/bin/mysqladmin -uroot password '123456' | /bin/true- name: create a database mysql_db: login_host: localhost login_user: root login_password: "123456" login_port: 3306 name: test encoding: utf8 state: present - name: create user mysql_user: login_host: localhost login_user: root login_password: "123456" login_port: 3306 name: test host: "192.168.137.%" password: "123456" priv: "test.*:ALL" state: present
构建 php 任务
vim php/tasks/main.yml
---
- name: install php yum: name=php state=present #安装 php
- name: install php-mysql yum: name=php-mysql state=present #安装 php 与 mysql 交互的插件
------------------------------------------------------------------------
# 一次安装多个软件格式:
- name: install php yum: name: ['php','php-mysql' , 'php-gd'] state: installed
编写整个任务入口文件
vim /etc/ansible/lamp/roles/site.yml
---
- name: prepare build remote_user: root hosts: web_servers # 要执行的 roles,确保 roles 目录下有同名的文件夹roles: - prepare# 给任务打标签,方便单独测试tags: prepare - name: LAMP build remote_user: root hosts: web_servers roles: - mysql tags: mysql - name: LAMP build remote_user: root hosts: web_servers roles: - php tags: php - name: LAMP build remote_user: root hosts: web_servers roles: - httpd tags: httpd
# 根据 tags 标签测试服务
ansible-playbook -C /etc/ansible/lamp/roles/site.yml -t httpd# 开始部署
ansible-playbook -i /etc/ansible/hosts /etc/ansible/lamp/roles/site.yml
相关文章:

Ansible-Playbook
目录 1、概念介绍 roles 角色 playbook 核心元素 ansible-playbook 命令 playbook 简单案例 2、Ansible 变量 自定义变量 facts 变量 Palybook 部署 LAMP ansible 端安装 LAMP playbook 系统环境脚本 构建 httpd 任务 构建 mariadb 任务 构建 php 任务 编写整个任务…...
UE5常见问题处理笔记
一、C工程中的文件出现很多头文件找不到,比如:#include CoreMinimal.h文件提示找不到。 解决方法:在UE编辑器中选择菜单Tools -> Refresh Visual Studio Project。 二、莫名其妙的编译错误。 解决方法,找到工程根目录下的Bi…...

docker中hyperf项目配置虚拟域名
在学习hyperf框架时遇到一些问题,这里是直接用了docker环境 下载镜像运行容器 docker run --name hyperf -v /data/project:/data/project -p 9501:9501 -itd -w /data/project --privileged -u root --entrypoint /bin/sh 镜像ID配置docker-compose.yml version…...

PID闭环控制算法的学习与简单使用
平台:matlab2021b,Vivado2018 应用场景和理解 一个早餐店,假如一天都有生意,生意有的时间很火爆,有时候又一般,老板又是个实在人,只知道在后厨蒸包子。由于包子蒸熟需要一定的时间,老…...

【无刷电机学习】光耦HCNR200基本原理及应用(资料摘抄)
【仅作自学记录,不出于任何商业目的。如有侵权,请联系删除,谢谢!】 本文摘抄翻译自: https://docs.broadcom.com/wcs-public/products/application-notes/application-note/331/6/av02-1333en-an_5394-16jul10.pdfhtt…...
【LeetCode】1768_交替合并字符串_C
题目描述 给你两个字符串 word1 和 word2 。请你从 word1 开始,通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾。 返回 合并后的字符串 。 https://leetcode.cn/problems/merge-strings-al…...
C#解析JSON
https://blog.csdn.net/weixin_43046974/article/details/131449900 C#解析JSON 1. JSON定义2. JSON一般构成及解析方法3. 解析举例子 1. JSON对象解析,只包含一层对象{}2. 嵌套JSON对象解析,包含多层对象{}3. JSON数组解析1(数组循环遍历&…...
AI图像识别算法助力安全生产*提升风险监测效率---豌豆云
2024年开年来安全生产事故频发,工厂爆炸、工程坍陷等重大安全生产事故的发生再次为我们敲响了警钟。 安全生产是企业发展的生命线,而传统的安全监测手段存在盲区和延迟,难以及时发现和应对潜在风险。 AI图像识别算法通过利用先进的计算机视…...

CSS技巧:实现两个div在同一行显示的方法
css如何让两个div在同一行显示 - web开发 - 亿速云 在Web开发中,经常遇到需要将多个元素水平排列在同一行的情况。其中一个常见的需求是将两个div元素放置在同一行上,使它们并排显示。在本文中,我们将介绍几种实现这一效果的CSS方法。 1. 使…...

【Unity】Node.js安装与配置环境
引言 我们在使用unity开发的时候,有时候会使用一些辅助工具。 Node.js就是开发中,经常会遇到的一款软件。 1.下载Node.js 下载地址:https://nodejs.org/en 2.安装Node.js ①点击直接点击Next下一步 ②把协议勾上,继续点击…...

Vue3:使用 Composition API 不需要 Pinia
在 Vue.js 开发的动态环境中,在单个组件中处理复杂的业务逻辑可能会导致笨重的文件和维护噩梦。虽然 Pinia 提供集中式状态管理,但仅依赖它来处理复杂的业务逻辑可能会导致代码混乱。本文探讨了使用 Composition API 的替代方法,说明开发人员…...
ExoPlayer 播放视频黑屏的解决方法
最近项目中在使用 ExoPlayer 来进行视频的播放,开发过程中遇到了部分视频打开后黑屏的问题,报错日志如下。 E Audio codec error android.media.MediaCodec$CodecException: Error 0xe E Playback error androidx.media3.exoplayer.ExoPlaybackExcept…...

C语言初阶—数组
数组是一组相同类型元素的集合。 在C99标准之前,数组的大小必须是常量或常量表达式。 在C99标准之后,数组的大小可以是变量,可以支持变长数组,但变长数组不能初始化。 不完全初始化,剩余的元素默认初始化为0 。 数组访…...
飞桨(PaddlePaddle)数据预处理教程
文章目录 飞桨(PaddlePaddle)数据预处理教程1. 安装飞桨2. 了解飞桨的数据预处理方法3. 应用单个数据预处理方法4. 组合多个数据预处理方法5. 在数据集中应用数据预处理5.1 在框架内置数据集中应用5.2 在自定义数据集中应用 6. 总结 飞桨(Pad…...

MYSQL C++链接接口编程
使用MYSQL 提供的C接口来访问数据库,官网比较零碎,又不想全部精读一下,百度CSDN都是乱七八糟的,大部分不可用 官网教程地址 https://dev.mysql.com/doc/connector-cpp/1.1/en/connector-cpp-examples-connecting.html 网上之所以乱七八糟,主要是MYSQL提供了3个接口两个包,使用…...
并发编程中常见的设计模式,c++多线程如何设计
C多线程设计(任务的“多对一”、“一对多”、“多对多”情况 该如何设计线程?) C书籍中并未找到对多线程设计,有很完整详细的总结!!C并发编程书籍中也只是一些理论或则零散的多线程实例。无奈,…...

解决android studio build Output中文乱码
1.效果如下所示: 代码运行报错的时候,Build Output报的错误日志中中文部分出现乱码,导致看不到到底报的什么错。 2.解决办法如下: 点击Android studio开发工具栏的Help-Edit Custom VM Options....,Android studio会…...

[云原生] K8s之pod进阶
一、pod的状态说明 (1)Pod 一直处于Pending状态 Pending状态意味着Pod的YAML文件已经提交给Kubernetes,API对象已经被创建并保存在Etcd当中。但是,这个Pod里有些容器因为某种原因而不能被顺利创建。比如,调度不成功(…...

[Unity3d] 网络开发基础【个人复习笔记/有不足之处欢迎斧正/侵删】
TCP/IP TCP/IP协议是一 系列规则(协议)的统称,他们定义了消息在网络间进行传输的规则 是供已连接互联网的设备进行通信的通信规则 OSI模型只是一个基本概念,而TCP/IP协议是基于这个概念的具体实现 TCP和UDP协议 TCP:传输控制协议,面向连接,…...
Tomcat的配置文件
Tomcat的配置文件详解 一.Tomcat的配置文件 Tomcat的配置文件默认存放在$CATALINA_HOME/conf目录中,主要有以下几个: 1.server.xml: Tomcat的主配置文件,包含Service, Connector, Engine, Realm, Valve, Hosts主组件的相关配置信息&#x…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...

算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...

nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...

Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...