本來打算連假走塔塔加抒發一下最近累積的壓力,不過天公不做美,連續下了幾天的雨,到了塔塔加遊客中心以後就決定往回走了。
由於下午的關係,阿里山到塔塔加的路並不好走,中途有部份地段有落石,也有路基不穩的狀況,建議上山之前還是要注意一下道路狀況。
塔塔加遊客中心,除了有賣紀念品以外,也有阿里山生態的教育影片,二樓則有餐廳。餐廳主要是以桌菜為主,雖然有單點但價位都不低,倒是 200 元的單人套餐份量和品質都很棒。
塔塔加遊客中心 200 元的單人套餐
軟體開發、伺服器和生活瑣事
本來打算連假走塔塔加抒發一下最近累積的壓力,不過天公不做美,連續下了幾天的雨,到了塔塔加遊客中心以後就決定往回走了。
由於下午的關係,阿里山到塔塔加的路並不好走,中途有部份地段有落石,也有路基不穩的狀況,建議上山之前還是要注意一下道路狀況。
塔塔加遊客中心,除了有賣紀念品以外,也有阿里山生態的教育影片,二樓則有餐廳。餐廳主要是以桌菜為主,雖然有單點但價位都不低,倒是 200 元的單人套餐份量和品質都很棒。
塔塔加遊客中心 200 元的單人套餐
一般 grep 只會將出現關鍵字的那一行文字顯示出來,例如:
johnroyer@box:~/logs$ zgrep 'parse' *gz
2016-02-27.log.gz:[2016-02-27 12:00:35] local.INFO: DOMDocument cannot parse XML: Premature end of data in tag html line 2
2016-02-27.log.gz:[2016-02-27 12:00:36] local.INFO: DOMDocument cannot parse XML: Premature end of data in tag html line 2
2016-02-27.log.gz:[2016-02-27 12:01:08] local.INFO: DOMDocument cannot parse XML: Premature end of data in tag html line 2
....
但有時顯示出來的訊息只是 function call stack trace 的其中一行,單看這一行無法理解到底發生了什麼事情。
遇到這種情況時,可以透過參數「-A」和「-B」來設定保留前後文:
johnroyer@box:~/logs$ zgrep 'Exception' *.gz -A 5 -B 2
[2016-05-29 23:41:22] production.INFO: RuntimeException: https://theinitium.com/newsfeed/
[2016-05-29 23:41:22] production.INFO: DOMDocument cannot parse XML: PCDATA invalid Char value 8
[2016-05-29 23:41:23] production.ERROR: exception 'RuntimeException' with message 'Invalid host label, check its content' in /home/segm/prod/www-crawler/vendor/league/url/src/Components/Host.php:164
Stack trace:
#0 /home/segm/prod/www-crawler/vendor/league/url/src/Components/AbstractSegment.php(47): LeagueUrlComponentsHost->validate('rss_Content.jsp')
#1 /home/segm/prod/www-crawler/vendor/league/url/src/Components/AbstractSegment.php(39): LeagueUrlComponentsAbstractSegment->set('rss_Content.jsp')
#2 /home/segm/prod/www-crawler/vendor/league/url/src/Components/Host.php(72): LeagueUrlComponentsAbstractSegment->__construct('rss_Content.jsp')
#3 /home/segm/prod/www-crawler/vendor/league/url/src/AbstractUrl.php(226): LeagueUrlComponentsHost->__construct('rss_Content.jsp')
.....
上面的範例是關鍵字前保留 2 行,往後保留 5 行。
以前在 FreeBSD 上找不到什麼比較好的 Redmine 啟動方法,當時找到最好的解法是在 Nginx 上面安裝 Passenger 將 Request 轉給 Redmine 執行。
但 passenger 需要在 compile time 手動將 module 編譯進去,若遇到 Nginx 版本更新,還要在手動為了 passenger 設定一次,實在很麻煩。
後來終於找到比較簡單的方法,就是在 Redmine 的 GemFile 加上「Thin」:
gem "rails", "4.2.5.2"
gem "jquery-rails", "~> 3.1.4"
gem "coderay", "~> 1.1.0"
gem "builder", ">= 3.0.4"
....
gem "roadie-rails"
gem "thin"
之後 bundler 安裝時就會自動把對應的 thin 版本拉下來。再來執行「thin config -C config.yml」便會建立一個預設的設定檔:
---
chdir: /home/zeroplex/redmine
environment: development
address: 0.0.0.0
port: 3000
timeout: 30
log: /home/zeroplex/redmine/log/thin.log
pid: tmp/pids/thin.pid
max_conns: 1024
max_persistent_conns: 100
require: []
wait: 30
threadpool_size: 20
daemonize: true
將設定檔的「chdir」設定成 Remine 跟目錄,再來執行「thin start -C config.yml」就能把 Redmine 跑起來了。
若機器上只有 thin 在跑 web server,那就讓他處理外部連線就好。若原本就有其他 web server 像是 Nginx 之類的,可以參考官網說明,設定 proxy 在 web server 把 request 轉給 thin。
較新的 PHP 專案都會在 composer require_dev 自帶 phpunit,這個時候要執行 phpunit 都應該要使用專案中設定的 phpunit 版本:
$ cd /path/to/repository
$ vendor/bin/phpunit
若該專案沒有設定 phpunit 時,才使用系統上,或是 composer global 的 phpunit:
$ cd /path/to/repository
$ ~/.composer/vendor/bin/phpunit # or "phpunit" for system global
不過這實在有點麻煩,所以乾脆寫 script 處理掉:
phpunit() {
REPO_PHPUNIT=`pwd`"/vendor/bin/phpunit"
if [ -e $REPO_PHPUNIT ]; then
echo "... Run by vendor/bin/phpunit ..."
$REPO_PHPUNIT $*
else
~/.composer/vendor/bin/phpunit $*
fi
}
這樣一來,只要執行 phpunit 就會自動去檢查專案底下是否有 phpunit 可以用;若沒有則自動使用系統的 phpunit。