What I Learnt Today 2022-01-22

如何解决 iCloud 文件上传时进度卡住的问题

可以尝试执行这个命令来解决:

1
killall bird

如何调试 launchd 服务

Homebrew Services

通过 Homebrew 安装的服务(如: MySQL, Redis 等)可以通过 brew services 这个命令来管理

列出所有通过 Homebrew 安装的服务

1
brew services list

输出:

Name              Status User File
consul            none
dbus              none
dnsmasq           none
elasticsearch     none
emacs             none
emacs-plus@27     none
kibana            none
libvirt           none
logstash          none
mysql@5.7         none
nginx             none
nginx-full        none
offlineimap       none
openresty         none
php               none
postgresql        none
privoxy           none
rabbitmq          none
redis             none
shadowsocks-libev none
supervisor        none
tomcat@7          none
tomcat@8          none
unbound           none
vault             none
zookeeper         none

启动和关停服务

1
2
brew services start mysql@5.7
brew services stop mysql@5.7

启动服务并将服务设置为开机自启动

1
sudo brew services start mysql@5.7

编写 launchd 服务

有时需要将自己编写的脚本通过 launchd 变成后台服务,可以这样做:

launchd 服务描述文件

编写一个文件,命名为 com.mycompany.demoscript.plist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LimitLoadToSessionType</key>
<string>Aqua</string>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>com.github.lululau.jianyue-helper</string>
<key>ProgramArguments</key>
<array>
<string>/Users/liuxiang/bin/jianyue-helper</string>
<string>/Users/liuxiang/Documents/jianyue</string>
<string>7026</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

其中 ProgramArguments 的值是一个数组,其中的元素为要执行的程序的名称和它的参数

启动和关停服务

1
2
launchctl load -w com.mycompany.demoscript.plist // 加载并启动服务
launchctl unload com.mycompany.demoscript.plist // 停止服务

将服务设置为开机自启动

com.mycompany.demoscript.plist 文件放到 ~/Library/LaunchAgents 目录下即可

调试 launchd 服务

Homebrew 安装的服务都有自己的日志系统,服务出现问题时我们可以通过查看该服务的日志进行排查。

对于自己编写的服务,遇到问题时如何排查呢,当然可以设置自己的日志系统, 也可以在服务对应的脚本程序中使用 logger 命令来 向系统写入日志,并用 log 命令查看这些系统日志。

即便如此,还是没有办法看到服务程序的标准输出和标准错误,可以在服务描述文件中指定标准输出和标准错误的输出文件:

1
2
3
4
<key>StandardErrorPath</key>
<string>/tmp/mycommand.err</string>
<key>StandardOutPath</key>
<string>/tmp/mycommand.out</string>

log 命令

log 命令有几个子命令,其中的 show, stream 子命令可以用来查看系统日志

show 查看历史日志

show 子命令的选项有:

  • --info--debug 只查看 INFO 或 DEBUG 级别的日志
  • --last time[m|h|d]: 只输出最近 time 分钟(m) / 小时(h) / 天(d) 的日志

stream 查看从当前时刻开始的日志,并且会跟随监视日志(相当于 tail -f

stream 子命令的选项有:

  • --level info|debug 只查看 info / debug 级别以上的日志

过滤机制

  • --process

    showstream 都可以通过 --process 选项指定一个 PID 或进程名称来对日志进行过滤

  • --predicate

    可以通过 --predicate 选项指定一个过滤表达式来对日志进行过滤

    • 过滤表达式由一个或多个 [key] [operator] [value] 形式组成,例如: ~process == "logger"​~
    • 常用的 key 有:
      • process 进程名称
      • eventMessage 日志内容
      • logType: default, info, debug
    • 常用的 operator 有:
      • == 字符串相等判断
      • BEGINSWITH 以字符串开头的判断
      • CONTAINS 包含字符串的判断
      • MATCHES 正则匹配,注意:正则是隐含有 ^$ 锚点的,例如正则 hello 不能匹配 hello world, 要想匹配 hello world 则需要使用正则 hello.*

示例

  • 最近 20 分钟内使用 logger 记录的日志
    1
    log show --info --debug --predicate 'process == "logger"' --last 20m
  • 最近 24 小时内日志内容匹配指定正则的日志
    1
    log show --info --debug --predicate 'eventMessage MATCHES[cd] ".*log\\s+test.*er.*"' --last 24h
  • 持续监视日志中包含 hello 字符串的日志
    1
    log stream --level debug --predicate 'eventMessage CONTAINS "hello"'