11.27.2014

Scala: error: forward reference extends over definition of value

Scala: Stream の再帰的な定義でエラー

 

自分自身を参照するような Stream を定義したら、エラーが出た。

 

エラーが発生する例

1
2
3
4
5
6
7
scala> def f(x: Int) = {
     |   val xs: Stream[Int] = x #:: xs.map(_ + 1)
     |   xs.tail
     | }
:17: error: forward reference extends over definition of value xs
         val xs: Stream[Int] = x #:: xs.map(_ + 1)
                                     ^

 

対応方法

lazy val にすれば OK。

1
2
3
4
5
6
7
8
scala> def f(x: Int) = {
     |   lazy val xs: Stream[Int] = x #:: xs.map(_ + 1)
     |   xs.tail
     | }
f: (x: Int)scala.collection.immutable.Stream[Int]
 
scala> f(3).take(10).toList
res8: List[Int] = List(4, 5, 6, 7, 8, 9, 10, 11, 12, 13)

 

 

References

11.25.2014

AdTech x Scala x Performance Tuning

アドテク×Scala meetup で登壇してきました

 

ありがたいことに、ひょんなことから声を掛けていただき、去る 11月20日
サイバーエージェント社で行われた『アドテク×Scala meetup』で少しだけお話をさせていただきました。

 

tl;dr

 

感想

  • アドテクを支えるScala - Ad Generationの場合
    • アドジェネさん、Spray/Actor ベースで動いているのかー。
  • Dynalystが広告配信で使っている技術(Spray×Akka×Kamon×Zabbix)
  • アドテク×Scala×パフォーマンスチューニング
    • 緊張しました。 200人もの大人数の前で話したのは初めてです。
    • インフラ目線の内容も織り交ぜ、自分自身が普段心がけていることをまとめました。
    • アドテク以外の開発でも参考になる部分はあると思います。
  • 軽量言語メインの 文系エンジニアだった自分が Scalaのシステム開発に携わることになった経緯
    • 馬の人だー。
  • 座談会
    • OE(@OE_uia)さん の貫禄の回し。
    • あのベテラン司会者のような落ち着きは、どこから生まれるのだろうか。
    • ご質問くださった皆様、どうもありがとうございました。

 

全体を通して

  • 与えられた発表時間はプレゼンに集中し、後で質問を受け付けるというスタイル。
    発表者側としてはとてもやりやすかった。
  • Spray/Actor ベースのシステム、十分に枯れてきた感がある。
    早いところプロダクションで作ってみたい。
  • 無料で振る舞われたビール & 寿司に感動。さすがサイバーエージェントさんや。
    (こちらはスタッフ & 登壇者専用) 
    Photo 2014 11 20 20 56 20 
  • 人気沸騰中の Scala ガール (AdTech Studio Girls Blog) に会えました!
  • 当日だけでなくイベントの準備に奔走されたCA社の皆様、当日ご来場くださった皆様、
    本当にありがとうございました!
    (こちらは開場前の準備風景)
    Photo 2014 11 20 18 36 53 

 

11.07.2014

Integrating Your Python Projects with Travis-CI and Coveralls

Python: GitHub 上のプロジェクトを Travis-CI, Coveralls と連携する

 

GitHub でパブリックなプロジェクトを作ったら、無料でCI環境とカバレッジ環境を手に入れることが可能。
これを利用しない手はない。

以下、具体例として一つの小さなプロジェクトを作りながら説明する。

 

Step 1: GitHub リポジトリ作成

setup.py で管理された Python プロジェクトを作る。

ディレクトリ構成

構成の一例。

.
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── setup.py
├── src
│   └── yourpackage
│       ├── __init__.py
│       └── yourmodule.py
└── tests
    ├── __init__.py
    └── test_yourmodule.py

 

アプリケーション/ライブラリの実装

ソースコードは src ディレクトリ配下にまとめる。

ここでは例として yourpackage というパッケージと、適当な数値計算を行うyour_function という関数を用意した。

__init__.py にインポート対象(クラス/関数)を書くのを忘れずに。

src/__init__.py
1
from .yourmodule import your_function
src/yourmodule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
def your_function(x):
    ret = 0
    if x % 2:
        ret |= 1
    if x < 10000:
        ret |= 2
    if x == 10000:
        ret |= 4
    if x % 9 == 7:
        ret |= 8
    if x / 2000 == 6:
        ret |= 16
    return ret
テストコードの実装

テストコードは tests ディレクトリ配下にまとめる。

tests 自体もパッケージとして管理したほうが利便性がよいので、空の __init__.py を作る。
そして以下のようなテストコードを書いた。

tests/test_yourmodule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import unittest
from yourpackage import your_function
 
 
class TestYourModule(unittest.TestCase):
    def setUp(self):
        pass
 
    def test_your_function_zero(self):
        self.assertEqual(your_function(0), 2)
 
    def test_your_function_odd(self):
        self.assertEqual(your_function(1), 3)
 
    def test_your_function_greater_than_10000(self):
        self.assertEqual(your_function(10006), 8)
 
    def test_your_function_12345(self):
        self.assertEqual(your_function(12345), 17)

カバレッジ結果をわかりやすくするため、あえてカバレッジ率は 100% にならないようにしている。

setup.py セットアップスクリプトの記述

今回は必要ないが、他の Python ライブラリに依存があればここで記述する。

setup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from setuptools import setup, find_packages
 
setup(
    name='your-project-name',
    version='0.0.1',
    description='description for your project',
    author='your name',
    author_email='your email address',
    url='your url',
    install_requires=[
        # list your dependencies
    ],
    tests_require=[
        # dependencies for unit testing
    ],
    package_dir={'': 'src'},
    packages=find_packages('src'),
    include_package_data=True,
    test_suite='tests',
)
テストの実行

setup.py を使ってテストを実行する。以下のように表示されれば OK。

$ python ./setup.py test
running test
running egg_info
creating src/your_project_name.egg-info
writing src/your_project_name.egg-info/PKG-INFO
writing top-level names to src/your_project_name.egg-info/top_level.txt
writing dependency_links to src/your_project_name.egg-info/dependency_links.txt
writing manifest file 'src/your_project_name.egg-info/SOURCES.txt'
reading manifest file 'src/your_project_name.egg-info/SOURCES.txt'
writing manifest file 'src/your_project_name.egg-info/SOURCES.txt'
running build_ext
test_your_function_12345 (tests.test_yourmodule.TestYourModule) ... ok
test_your_function_greater_than_10000 (tests.test_yourmodule.TestYourModule) ... ok
test_your_function_odd (tests.test_yourmodule.TestYourModule) ... ok
test_your_function_zero (tests.test_yourmodule.TestYourModule) ... ok
 
----------------------------------------------------------------------
Ran 4 tests in 0.000s
 
OK

ここまでできたら、一旦 GitHub に公開リポジトリとして push する。

 

Step 2: Travis-CI の登録

  • https://travis-ci.org/ にアクセス
  • メニュー右上の Sign in with GitHub をクリックし、GitHub OpenID認証を承認
  • ログイン後、アカウント名 -> Accounts -> Repositories の画面で
    連携したいプロジェクトをチェック・オン
    Travis CI Free Hosted Continuous Integration Platform for the Open Source Community

 

Step 3: Coveralls の登録

  • https://coveralls.io/ にアクセス
  • メニュー右上の SIGN IN ボタンをクリックし、GitHub OpenID認証を承認
  • ログイン後、REPOS -> ADD REPOS ボタンをクリック
  • リストに対象リポジトリが表示されていなかったら、画面上部の SYNC GITHUB REPOS ボタンをクリック
  • 連携したいプロジェクトをチェック・オン
    Coveralls Test Coverage History Statistics

 

Step 4: .travis.yml の設置

プロジェクトルートに、.travis.yml という名前の設定ファイルを作れば
Travis-CI がそのファイルを読み取ってテストを走らせてくれる。

こちら (Travis CI: Building a Python Project) を参考に、以下のような内容で記述。

1
2
3
4
5
6
7
8
9
10
11
---
language: python
python:
  - "2.6"
  - "2.7"
install:
  - pip install coveralls
script:
  - coverage run --source=src setup.py test
after_success:
  - coveralls

install, script, after_success に Coveralls 連携のための記述を追加していることに注意。

この状態で GitHub に push を行えば、ほどなく(数分以内に)自動的に Travis-CI, Coverall の処理が開始される。

 

Step5: 結果確認

Travis-CI, Coverall ともに GUI ですぐに結果を確認できる。
またテストに失敗した場合は、自動的に通知メールが飛んでくる。 

  • Travis-CI
    Travis CI Free Hosted Continuous Integration Platform for the Open Source Community
  • Coveralls
    Mogproject skeleton python Coveralls Test Coverage History Statistics

    ファイル単位のカバレッジももちろん閲覧可能。
    Mogproject skeleton python Job 1 src yourpackage yourmodule py Coveralls Test Coverage History Statistics

 

Step 6: バッジの登録

Travis-CI, Coveralls ともに公式のバッジが用意されている。

  • Travis-CI
    Travis CI Free Hosted Continuous Integration Platform for the Open Source Community
  • Coveralls
    Mogproject skeleton python Coveralls Test Coverage History Statistics 

これらを README に貼り付ければ、GitHub 訪問者にとってもステータスが一目瞭然だ。
Mogproject skeleton python 

さいごに

今回は Python プロジェクトの例を挙げたが、setup.py やテストコードの準備さえ済めば、実に簡単に連携できる。

まさに朝飯前。『Web系エンジニアにとってテストコードを書くのは朝起きて歯磨きをするように当たり前のこと』との言もあったが、これらのサービスはさながら無料の朝食サービスのようなものだ。

より高度な使い方もできるので、詳細は各サービスのドキュメントを参照。以下はその一例。

  • master 以外のブランチと連携
  • pull request との連携 (マージする前に結果を確認できるので便利)
  • 通知先の拡張 (チャットサービス等と連携)
  • プライベートリポジトリとの連携 (有償)

Travis-CI, Coveralls ともに他の言語でも利用可能なので、今後も積極的に活用していきたい。

 

今回使用したコード

 

References

11.06.2014

Cheat Sheets for My Sake

自分向け各種チートシートまとめ

 

自分が忘れがち or 使用頻度の高い事柄だけ書いておく。

Shell Script Cheat Sheet

原則、Bourne Shell 互換のものを書く

  • 実行中のスクリプトがあるディレクトリをフルパスで取得
SCRIPT_DIR=$( cd "$( dirname "$0" )" && pwd -P )

この場合、実行スクリプト自身がシンボリックリンクだと正しい判定ができない。以下のような実装が必要。

function __readlink_f {
    local t="$1"; local n=
    (while [ "$t" ]; do cd $(dirname "$t"); n=$(basename "$t"); t=$(readlink "$n"); done; echo "$(pwd -P)/$n")
}

SCRIPT_PATH=$(__readlink_f "$0")
SCRIPT_DIR=$(dirname "${SCRIPT_PATH}")
  • 変数が未定義または空文字だった場合にデフォルト値を代入
NAME=${NAME:-"default_value"}
  • 特定ディレクトリ配下の条件を満たすファイルを削除
/usr/bin/find $PATH_TO_FIND -type f -name '*.gz' -mtime +$PRESERVE_DAYS -delete
  • パラメータの2個目以降を取得
$ f() { echo "${@:2}" }
$ f 1 2 3 4 5
2 3 4 5
  • シェルスクリプト終了時に一時ファイルを削除
TMP_FILE="/tmp/$(basename "$0").$$.tmp"
trap "rm -f ${TMP_FILE}" EXIT
  • [Linux] サーバに接続されているディスクのマウントポイントを列挙
df --output=source,target | grep ^/dev | awk '{print $2}'
  • コマンドの存在をチェック
# assert that all required commands exist
assert_command_exists() {
    while [ -n "$1" ]; do
        command -v $1 >/dev/null 2>&1 || {
            echo "Command '$1' is required but not installed. Aborting."
            exit 1
        }
        shift
    done
}
  • Yes/No プロンプト
# print prompt and return yes/no
prompt_yesno() {
    local prompt=$1
    read -p "$prompt [y/N]: " yn
    case "$yn" in
        [Yy]) return 0;;
        *) return 1;;
    esac
}
  • シェルスクリプト中のコマンドで失敗した場合に即終了とする

    • シェルの中で set -e
    • or シェル起動時に bash -e
  • ファイルの内容を入力と同時に書き換える (一時ファイルなし)

Bash 配列の操作

  • 標準入力から読み込んだ内容を 1行ずつ配列に格納する
IFS=$'\n' lines=($(cat))

または

declare -a lines    ### lines=() でも可
while IFS= read line; do
    lines+=("$line")
done
  • 配列の要素を全て削除
unset arr[@]
  • 配列のコピー
dst_arr=("${src_arr[@]}")
  • 配列の内容を表示
printf '%s\n' "${arr[@]}"

AWK Cheat Sheet

  • shebang
#!/usr/bin/env awk -f
  • 先頭の n 個の要素を除外
# Join all tokens except first n ones with a space
function drop(n) {
  s = "";
  for (i = n + 1; i <= NF; ++i) {
    s = (s == "" ? s : s " ") $i
  }
  return s;
}

実行例

$ echo '1 2 3 4 5' | awk 'function drop(n){s="";for(i=n+1;i<=NF;++i){s=(s==""?s:s" ")$i}return s} {print drop(2)}'
3 4 5

Git Cheat Sheet

  • リモートブランチをローカルに取得してチェックアウト
git checkout -t -b branch_name origin/branch_name
  • 直前コミットの author を修正
git commit --amend --author="Your Name <your_address@example.com>"
  • git push の時に、自動的に現在のブランチが対象になるようにする
git config --global push.default current
  • リモートブランチの削除
git push --delete origin branch_name
  • コマンドのエイリアスを設定する (checkout => co の例)
git config --global alias.co checkout
  • アップストリームの確認と設定
git branch -vv

git push -u [origin branch_name]
  or
git branch --set-upstream-to=origin/branch_name branch_name

MySQL Cheat Sheet

確認

  • データベース一覧
show databases
  • テーブル一覧
use <db_name>
show tables
  • テーブル定義
desc <db_name>;
  • ユーザ一覧
select host, user, password from mysql.user;
  • ユーザ権限
show grants for <user>@<host>
  • レプリケーション状態

スレーブノード上で

show slave status \G
  • サーバパラメータ
show variables like '%host';

変更

  • カラム名変更
alter table <table_name> change <old_column_name> <new_column_name> <type> <option>;
  • カラム削除
alter table <table_name> drop column <column_name>;
  • サーバパラメータ
set global <variable_name>=<value>

or modify /etc/my.cnf

  • AUTO_INCREMENTの値をリセット
ALTER TABLE <table_name> AUTO_INCREMENT = 1;
  • TIMESTAMP型の値を変更
UPDATE <table_name> SET <column_name> = 'YYYY-MM-DD hh:mm:ss' WHERE <condition>
  • パスワード変更
set password for 'root'@'localhost' = password('root');

バックアップ

  • DB全体
mysqldump -u root -x --all-databases > 出力ファイル名
  • 特定DB
mysqldump -u root データベース名 > 出力ファイル名
  • 特定テーブル
mysqldump -h ホスト名 -u ユーザ名 -p -t データベース名 テーブル名 > 出力ファイル名

Redshift Cheat Sheet

接続

  • psql で接続
psql -h <エンドポイントURL> -U <接続ユーザ> -d <データベース名> -p <ポート番号>

例: psql -h xxxxxx.xxxxxxxxxxxx.ap-northeast-1.redshift.amazonaws.com -U awsuser -d xxxxxx -p 5439

環境変数 PGPASSWORD=<パスワード> を指定すればパスワードの入力を省略可能。

プロンプト文字列を変える場合は -v PROMPT1='%m:%/# ' のように変数指定オプションを追加。

テーブル情報確認

  • テーブル一覧
\dt

クエリを直接実行する場合

SELECT DISTINCT tablename FROM pg_table_def WHERE schemaname = 'public' ORDER BY tablename;
  • テーブル定義の確認
\d+ <テーブル名>

クエリを直接実行する場合

SELECT * FROM pg_table_def WHERE tablename = '<テーブル名>' AND schemaname = 'public';

テーブル定義変更

  • カラムの型を変更

新しいカラムを定義し、データを全てコピーし、そしてそのカラム名を変更するより方法がない。

ALTER TABLE <テーブル名> ADD COLUMN <一時的なカラム名> <正しいカラム定義>;
UPDATE <テーブル名> SET <一時的なカラム名> = <カラム名>;
ALTER TABLE <テーブル名> DROP COLUMN <カラム名>;
ALTER TABLE <テーブル名> RENAME COLUMN <一時的なカラム名> TO <カラム名>;

クエリの実行

  • ミリ秒単位の Unix time から DATETIME に変換
SELECT TIMESTAMP 'epoch' + <カラム名> * INTERVAL '0.001 s' AS time_stamp FROM <テーブル名>
  • 日本時間で表示
SELECT CONVERT_TIMEZONE('JST', TIMESTAMP 'epoch' + <カラム名> * INTERVAL '0.001 s') AS time_stamp FROM <テーブル名>

トラブルシューティング

  • データロードエラーの調査
SELECT DISTINCT
  name AS tablename,
  raw_line,
  query,
  starttime,
  filename,
  line_number,
  colname,
  err_code,
  err_reason
FROM
  stl_load_errors error,
  stv_tbl_perm perm
WHERE
  error.tbl = perm.id
ORDER BY
  starttime DESC
LIMIT 20;

参考

Ansible Cheat Sheet

  • コマンド結果によって処理の要否を判断する
    • register を使ってコマンド実行結果を変数に格納。
    • ignore_errors は必須。changed_when, failed_when は表示を見やすくするために。
- name: check if YOUR_MODULE is installed
  command: /usr/bin/test -e PATH_TO_THE_FILE
  ignore_errors: True
  changed_when: False
  failed_when: False
  register: is_installed
  tags: YOUR_MODULE

- name: install YOUR_MODULE
  ANSIBLE_MODULE: PARAMS
  when: is_installed | failed
  tags: YOUR_MODULE
- name: check if YOUR_PIP_MODULE is installed
  command: pip show YOUR_PIP_MODULE
  ignore_errors: True
  changed_when: False
  failed_when: False
  register: check_installed
  tags: YOUR_PIP_MODULE

- name: install YOUR_PIP_MODULE
  pip: name={{ item }} state=present
  with_items: YOUR_PIP_MODULE_URL
  when: check_installed.stdout == ''
  tags: YOUR_PIP_MODULE

11.05.2014

Ansible: Visualizing CloudWatch Metrics with Grafana

Ansible: Grafana で CloudWatch のメトリクスを可視化するための Playbook

 

tl;dr

Grafana に触れてみたいなら、まずは Grafana Play Home

 

目的
  • AWS CloudWatch の各種メトリクスを Grafana で見たい
  • Grafana の URL は SSL + ベーシック認証で保護したい
  • これらのセットアップ作業を Ansible で自動化したい

 

使ったもの
  • Amazon CloudWatch: AWS 標準の監視コンソール。メトリクスデータが蓄積している前提
  • Amazon EC2
    • Amazon Linux: インスタンスを1台立ち上げ、この中に全てをインストールする
  • Nginx: フロントエンドの Web サーバ。BASIC認証 + 自己署名証明書によるSSL通信を設定。
  • Grafana: メトリクスデータの可視化ツール
  • Graphite: メトリクスデータ管理システム
    • uWSGI: フロントエンド連携用に必要
    • MySQL: Graphite のデータストアとして使う
  • cloudwatch-dump: CloudWatch のメトリクスデータを取得し、Graphite に流し込むために使用
  • Ansible: セットアップ(プロビジョニング)の自動化

 

コード

こちらのリポジトリに Vagrant + Ansible コード一式と再現手順を書いた。

必要なソフトウェア/プラグインをインストール後、vagrant up を行えば以下のような Grafana の画面に触れられるようになる。

Grafana Grafana

Grafana のロゴが表示されないのは https 通信をしているためで、表示させるにはソースコードに手を入れる必要がありそう。

 

はじめに

システム監視の目的は大きく「異常検知」と「トレンド分析」の2つに分けられる。

また一般に、「トレンド分析」がその対象者に応じて、例えば「システム利用者向け分析」「システム管理者向け分析」「経営判断層層向け分析」の3つのように分類できると、スッキリとしたシステムになりやすい。

 

今回の構成ではメトリクスデータは一旦 CloudWatch に集約される想定である。

異常検知は CloudWatch が持ち合わせている Alarm 機能で対応する。
Simple Notification Service を使うことでメール送信だけではなく、携帯端末にpush通知を行ったり、特定のURLにhttpリクエストを投げたり、オートスケールを実現したりなど工夫次第でできることは多い。

次に、そのメトリクスデータを一式 Graphite に投入する。
これを Grafana のようなフロントエンドで可視化することにより、異なる対象者に向けたダッシュボードを簡単に作ることができる。
生成されたグラフを週次レポートのような形で定期的に発信するのもよい。

 

構成イメージ

解説

 

Vagrantfile
  • プラグイン dotenv を使うことでアカウント固有の定義を別ファイル(.env)に分離
  • (コスト節約のため)米国東部リージョンに t2.micro インスタンスを1個新規構築する
  • Ansible のロールの中で使う変数は、extra_vars として引き渡す
Role: aws-scripts-mon
  • これは本来監視される側のセットアップである
  • CloudWatch の標準機能だけは取得できない Linux 内部の情報(メモリ/スワップ/ディスクスペース使用状況)を CloudWatch に送信する
  • 今回は、ec2-user の ~/aws-scripts-mon ディレクトリ配下にモジュール一式を配置し、Cron で 5分おきにレポーティングが実行されるよう仕掛けた
  • CloudWatch API のアクセスには、EC2 構築時とは別の IAM ユーザ (cloudwatch) を準備した
Role: nginx
  • もちろん Grafana は Apache でも動作する(その方が簡単だ)が、今回は Web サーバとして Nginx を採用する
  • このロールの中で自己署名証明書を作成し、/etc/nginx/cert ディレクトリ配下に配置した
  • 実際のSSLサイトの設定は、Grafana のインストール後に実施する
Role: mysql
  • デフォルトの SQLite でも動作するが、運用を考えるなら MySQL 等のほうが堅い
  • Amazon Linux はデフォルトで利用可能な EPEL リポジトリに対して yum install するだけ  
Role: graphite
  • jsmartin/ansible-graphite を参考にした
  • python-carbon を yum でインストールしたのは、起動スクリプトの有り物を使いたかったので
  • 最初は graphite-web も yum で導入したのだが、/opt/graphite/bin 以下のモジュールがインストールされずエラーが出て面倒なことになったので、最終的にこちらは pip で入れることにした
  • そのため、carbon 関係はFHS準拠っぽいディレクトリ構成なのに graphite の場所は /opt/graphite 配下という状態になっている
  • コマンドによって処理の要否を判定する雛形はこちらにも書いた
  • Whisper のデフォルトのデータ間隔・保持期間を 5分・2年 に書き換えている。(storage-schemas.conf)
    こうすることで長期間の分析をしてもデータが重くならない。(逆に1分単位の分析はできなくなる)
  • 起動がうまくいかない場合は、大抵 /var/log/graphite-web.log を見れば原因がわかるはず 
Role: cloudwatch-dump
  • 自作のダンプツールを pip でインストール
  • ec2-user の ~/cloudwatch-dump ディレクトリ配下にシェルを置き、Cron で 1時間に1回(*:05)、graphite にデータを流し込む
  • 何かあった時でもデータを再投入できるよう、~/cloudwatch-dump/logs に直近のログを残している
    (ローテーションは logrotate を使ったほうが良かったかも)
  • シェルスクリプトの中で、メトリクスパス中に含まれるEC2インスタンスIDをニックネームへの変換している
Role: elasticsearch
  • RPM のダウンロード先を指定して、yum install するだけ
Role: grafana
  • Grafana 自体は独立したツールなので、インストールは素直に終わる
  • カスタマイズは config.js をテンプレートエンジンに乗せて行う。Grafana のバージョンによって微妙に項目が変わっているので注意
  • 最後に Nginx の SSL サイト設定と、BASIC認証用のファイルを作って完了
 
References

Related Posts

11.03.2014

Mac: Upgrading to OS X Yosemite

Mac: OS X Yosemite にアップグレードした際のメモ

 

reattach-to-user-namespace のアップデート

HomeBrew でインストールした reattach-to-user-namespace で警告が出た。

warning: reattach-to-user-namespace: unsupported new OS, trying as if it were 10.6-10.9
warning: _vprocmgr_move_subset_to_user failed
warning: reattach-to-user-namespace: unable to reattach

reattach-to-user-namespace の最新版をインストールすればよい。

$ brew upgrade reattach-to-user-namespace

 

テキストエディタなどで Ctrl-N (カーソルを一行下へ移動) が効かなくなる

なぜか、システム環境設定 Keyboard -> Input Sources -> Japanese -> Windows-like shortcuts に
チェックが入っていると、Emacs ライクなキーバインドである Ctrl-N が効かなくなるようだ。

チェックオフにして解決。

Screenshot 11 3 14 13 33

ハードウェアドライバの更新

11.01.2014

cloudwatch-dump - Dump All the CloudWatch Metrics Statistics

Python: CloudWatch のメトリクスデータを全て出力するスクリプト

 

概要

1. 特定リージョンの AWS CloudWatch からメトリクスの一覧を取得し、
2. その全てのメトリクスに対して、ある期間を一定の単位時間で「平均」「合計」の統計値を取得し、
3. その結果(メトリクス、数値、タイムスタンプ)を Graphite に投入可能な形式で出力する

そんな Python スクリプトを作成。

 

モチベーション

やりたいことは、CloudWatch のデータを Grafana で見たいだけ。

Grafana AWS

はじめは Fluentd + fluent-plugin-cloudwatch + fluent-plugin-graphite を使って流し込んでいたのだが、

  • メトリクスと統計方法(Average, Sum, Maximum)を1個1個指定しなければいけなかったり (将来にわたってメンテが必要)
  • ちらほらデータの欠落が見られたり
  • バッファリングの関係か、データが更新されるタイミングを制御しづらかったり
  • 特定期間だけリトライしたい場合に難しかったり
といったことがあったので、1時間おきのバッチ処理で一括インポートをすることにした。
 
とはいえ悩みどころなのが統計方法。
CloudWatch では各サービス・各メトリクスごとに推奨の(意味のある)統計方法が異なっている。

しかし今回は割り切って、全メトリクスについて 平均(Average)、合計(Sum) を取得することにした。
物によっては Maximum を得たい場合もあるが、一旦は目を瞑る。

 

今後の課題

  • CloudWatch の APIリクエストも決して無制限で使えるわけではないので、極力無駄なリクエストは減らしたい。
    (現時点では100万件/月まで無料, それ以降は1,000件ごとに0.01USDの課金)
    CPU使用率の Sum など、結局個別に指定する他ないのか。
  • 個別のメトリクス統計方法の指定 (DynamoDB の ItemCount の Maximum など) をできるようにするか
  • 並列化をして高速に
  • ユニットテストを充実させる

 

導入方法、注意事項についてはリポジトリの README参照。