Page List

Search on the blog

ラベル UNIX の投稿を表示しています。 すべての投稿を表示
ラベル UNIX の投稿を表示しています。 すべての投稿を表示

2017年2月15日水曜日

データ圧縮してscpする

 4.5GBあるファイルをscpで転送していて中々終わらずイライラしていたら、

「Dash! C Capital!」

という声が隣から聞こえた。
最初は何のことか分からなかったが、「-Cをつけるとデータ圧縮とscp同時にしてくれて速くなるよ。」ということだった。

$ scp -C source user@server:/path/to/backup

scpが遅い場合は、-Cをつける。今日もまた一つ新しい学びがあった。

2017年1月13日金曜日

/usr/bin、/usr/sbin、/usr/local/binなどの違い

 自分が作ったスクリプトをどこに置くべきか迷っていたら、これらの違いについて気になったので調べてみた。違いは以下のとおり。

ディレクトリ名 説明 中に入っているバイナリ例
/bin single user modeでも利用できるバイナリ。 date、cat、ls、bash、cdなど
/sbin single user modeでも利用できるバイナリ。
supervisor権限が必要なもの。
fsck、mount、ping、dmesgなど
/usr/bin システム全体で一般的に利用されるバイナリ。 make、awk、java、ccなど
/usr/sbin システム全体で一般的に利用されるバイナリ。
supervisor権限が必要なもの。
sshd、syslogd、httpdなど
/usr/local/bin システム全体で一般的に利用されるバイナリ。
システムパッケージに管理されていないもの。
tmux、subl、spark-shellなど
/usr/local/sbin システム全体で一般的に利用されるバイナリ。
supervisor権限が必要なもの。
システムパッケージに管理されていないもの。
logrotateなど

ということで、自作のバイナリは/usr/local/bin、または、/usr/local/sbinに入れるのが正しいらしい。
ちなみに、システム全体ではなく自分が使うだけのバイナリであれば、~/binに入れるらしい。

参考
Differences between /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin, /usr/local/sbin [duplicate]

2016年8月22日月曜日

INETドメインとUNIXドメイン

ソケットには、INETドメインソケットとUNIXドメインソケットが存在する。

INETドメイン
異なるマシンで動作しているプロセス間の通信を行うためのソケット。

UNIXドメイン
同じマシン内で動作しているプロセス間の通信を行うためのソケット。
INETドメインソケットでもループバックアドレスを利用することで同一マシン内の通信はできるが、UNIXドメインソケットの方が高速である。

INETドメインソケットのサンプル

inet_server.py

bindするときにIP、PORTを指定する。

import socket

IP = '127.0.0.1'
PORT = 5005
BUFFER_SIZE = 1024

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((IP, PORT))
s.listen(1)
conn, addr = s.accept()
while 1:
 data = conn.recv(BUFFER_SIZE)
 if not data:
  break
 msg = data.decode('utf-8')
 msg = msg[::-1]
 conn.send(msg.encode('utf-8'))
conn.close() 

inet_client.py

import socket

IP = '127.0.0.1'
PORT = 5005
BUFFER_SIZE = 1024

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
msg = "ABCDEFG"
s.send(msg.encode('utf-8'))
data = s.recv(BUFFER_SIZE)
print (data.decode('utf-8'))
s.close()

プロセスIDからINETドメインソケットを調べる。
$ ps -ef | grep python
  501  9165  2011   0 11:51PM ttys000    0:00.04 python inet_server.py
$ lsof -n -i -P | grep 9165
python3.5  9165 kenjih    3u  IPv4 0xf27949601620cf2b      0t0  TCP 127.0.0.1:5005 (LISTEN)

UNIXドメインソケットのサンプル

unix_server.py

bindするときにファイル名を指定する。
UNIXドメインソケットでは、アドレス・名前空間としてファイルシステムを使用する。

import socket
import os

PATH = '/tmp/sample.sock'
BUFFER_SIZE = 1024

s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
os.unlink(PATH)
s.bind(PATH)
s.listen(1)
conn, addr = s.accept()
while 1:
 data = conn.recv(BUFFER_SIZE)
 if not data:
  break
 msg = data.decode('utf-8')
 msg = msg[::-1]
 conn.send(msg.encode('utf-8'))
conn.close() 

unix_client.py

import socket

PATH = '/tmp/sample.sock'
BUFFER_SIZE = 1024

s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(PATH)
msg = "ABCDEFG"
s.send(msg.encode('utf-8'))
data = s.recv(BUFFER_SIZE)
print (data.decode('utf-8'))
s.close()

プロセスIDからUNIXドメインソケットを調べる。
$ ps -ef | grep python     
  501 11543  2011   0 12:02AM ttys000    0:00.04 python unix_server.py
$ lsof -n -P -U | grep 11543
python3.5 11543 kenjih    3u  unix 0xf279496017547fcb      0t0      /tmp/sample.sock

2016年6月24日金曜日

load averageとは

load averageとは?
  • load = システムが実行しているワークの単位。CPUリソースを使用している or CPUリソースを待っているプロセスの数。
  • load average = ある時間単位でのloadの平均。
確認方法
uptimeコマンドで。左から、直近1min, 直近5min, 直近15minのload average。
$ uptime
 0:51  up 1 day, 46 mins, 3 users, load averages: 2.05 1.87 2.10

数字が意味するものは?
シングルコアシステムの場合
 load average 2.50 = 1.50個のプロセスがCPUの空きを待っている。

 load average 0.70 = CPUは30%の時間でアイドル状態にある。

マルチコアシステムの場合
例: CPU4つの場合
load average 4.00 = 4つの異なるプロセスが4つの異なるCPUを使っている。

ということで、load averageがCPU数を超えるとヤバイ状態である。

CPU使用率との違い
シングルコアシステムでCPU使用率が100%というとヤバそうに聞こえる。
しかし、これだけだとシステムがヤバイ状態かどうなのかは何とも言えない。

例えばシステムで計算の多いバッチ処理を回していて、このバッチ以外には実行すべきプロセスがない場合。
CPU使用率100%、load average = 1。
これはバッチがCPUリソースを使えるだけ使って計算しているという状態で、ヤバくはない。

これに対して、webアプリケーションなどイベントドリブン系のシステムで、処理すべきイベントが多発したとき。
CPU使用率100%、load average = 5。
これはヤバい。平均して4つのプロセスが待ち状態にあるということなので、システムのスペックアップを考えた方がよい。

あと、CPU利用率は低いけど、load averageは大きいというパターン。
CPU使用率10%、load average = 10。
IOで処理が詰まってCPUリソースが使えてませんという状態。ボトルネックになっているIOを見つけましょう!という状態。もしくはCPUのコア数多いから減らしてもいいんじゃないという状態。

2016年4月23日土曜日

awkの連想配列を使ってユニークなデータ数を数える

サンプルファイル
 以下のようなファイルをサンプルとして用いる。
$ wc -l tmp.log 
 1000000 tmp.log
$ head tmp.log 
F 61
F 18
A 95
V 98
U 23
C 94
F 47
N 42
I 85
Q 28
1列目にアルファベット、2列目に数字があるような何らかのログファイルで、行数は100 万行。
このファイルの2列目のユニークなデータ数を数えたいとする。

sort | uniq
有名なイディオムを使うと、
$ cat tmp.log | awk '{print $2}' | sort | uniq | wc -l
100

だが、これは遅い。
手元の環境だと約12秒ほどかかる。

awkの連想配列
awk内で連想配列を使って値の出現数をカウントして、初めて出た時だけカウントするというやり方でやってみると、
cat tmp.log | awk '!seen[$2]++' | wc -l
100

速い!
手元の環境で0.7秒くらい。

ということで、sort | uniq するより awkの連想配列使った方がいいという話でした。

2015年2月22日日曜日

キャッシュヒット率の測定

 perfというツールを使ってキャッシュヒット率を測定してみた。
キャッシュの影響なんてたかが知れていると甘くみていたら、痛い目るので要注意。

キャッシュの用語
知らない用語がちらほらあったので、簡単にまとめておく。

L1、L2、L3キャッシュ
Level1、Level2、Level3の略。
それぞれ速度、容量に違いがある。

速度L1 > L2 > L3
容量L1 < L2 < L3

高速なキャッシュほど容量が小さくヒット率は低い。
容量の大きいキャッシュはヒット率は高いが、低速。

というトレードオフがある。

プロセッサは以下の順序で処理実行に必要なデータを探す。
①L1キャッシュにアクセスし、ヒットすれば処理実行。ミスの場合は、L2へ。
②L2キャッシュにアクセスし、ヒットすれば処理実行。ミスの場合は、L3へ。
③L3キャッシュにアクセスし、ヒットすれば処理実行。ミスの場合はメインメモリへ。

L1dキャッシュとL1iキャッシュ
L1dはLevel 1 data cache。
L1iはLevel 1 instruction cache。

data cacheは、データをキャッシュするためのキャッシュ。

instruction cacheはプロセッサによって実行される命令をキャッシュするためのキャッシュ。

命令をキャッシュするとはどういうことか?

ストアドプログラム方式では実行されるプログラムもメモリに格納されているため、プロセッサは実行する命令をメモリから読まなければいけない。
よってプロセッサから見ると命令もある種のデータなのである。

キャッシュサイズを参照
Debian系マシンではlscpuコマンドでキャッシュサイズを確認できる。
L1-L3トータルで3MB以上ある。予想してたよりも容量大きい。

kenjih$ lscpu
Architecture:          i686
CPU 操作モード:   32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
コアあたりのスレッド数:2
ソケットあたりのコア数:2
Socket(s):             1
ベンダー ID:       GenuineIntel
CPU ファミリー:   6
モデル:             42
ステッピング:    7
CPU MHz:               800.000
BogoMIPS:              4988.44
仮想化:             VT-x
L1d キャッシュ:   32K
L1i キャッシュ:   32K
L2 キャッシュ:    256K
L3 キャッシュ:    3072K

キャッシュヒット率を計測
Linuxのパフォーマンス解析ツールperfを使って、キャッシュヒット率を計測してみた。 例として、以下の2つの方法で行列の掛け算を行ったときのキャッシュヒット率を計測する。

プログラムA (a.cpp)
#include <iostream>
#include <vector>

using namespace std;

typedef vector<int> vec;
typedef vector<vec> mat;

const int N = 1024;

mat multiply(const mat &x, const mat &y) {
    int r = x.size();
    int m = y.size();
    int c = y[0].size();

    mat z(r, vec(c));
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < c; j++) {
            for (int k = 0; k < m; k++) {
                z[i][j] += x[i][k] * y[k][j];
            }       
        }
    }

    return z;
}

int main(int argc, char **argv) {
    
    mat x(N, vec(N));
    mat y(N, vec(N));

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            x[i][j] = i;
            y[i][j] = j;
        }
    }

    mat z = multiply(x, y);

    long long sum = 0;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            sum += z[i][j];
        }
    }

    cout << sum << endl;

    return 0;
}

プログラムB (b.cpp)
#include <iostream>
#include <vector>

using namespace std;

typedef vector<int> vec;
typedef vector<vec> mat;

const int N = 1024;

mat multiply(const mat &x, const mat &y) {
    int r = x.size();
    int m = y.size();
    int c = y[0].size();

    mat z(r, vec(c));
    for (int i = 0; i < r; i++) {
        for (int k = 0; k < m; k++) {
            for (int j = 0; j < c; j++) {
                z[i][j] += x[i][k] * y[k][j];
            }       
        }
    }

    return z;
}

int main(int argc, char **argv) {
    
    mat x(N, vec(N));
    mat y(N, vec(N));

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            x[i][j] = i;
            y[i][j] = j;
        }
    }

    mat z = multiply(x, y);

    long long sum = 0;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            sum += z[i][j];
        }
    }

    cout << sum << endl;

    return 0;
}

プログラムAとプログラムBの違いは、multiply関数のループの部分だけである。
プログラムAはi, j, kの順で、プログラムBはi, k, jの順でループを回す。

一見大した違いは無さそうであるが、キャッシュのヒット率によって大きな違いが生じる。

コンパイルは以下のように行った。

g++ -Wall -O2 a.cpp -std=c++0x -lm -o a

実行してみると、

プログラムA 9.260s
プログラムB 1.184s

となった。
約8倍ほどプログラムBの方が高速。

それぞれのプログラムでキャッシュ参照数、キャッシュミス数などを以下のコマンドで出力してみた。

perf stat -e cycles,instructions,cache-references,cache-misses ./a
結果は以下のとおり。

 プログラムA
 Performance counter stats for './a':

    27,363,421,784 cycles                    #    0.000 GHz                    
    11,880,422,836 instructions              #    0.43  insns per cycle        
        71,384,828 cache-references                                            
        57,242,356 cache-misses              #   80.188 % of all cache refs    

プログラムB
Performance counter stats for './b':

     3,618,482,791 cycles                    #    0.000 GHz                    
     6,495,956,182 instructions              #    1.80  insns per cycle        
         9,516,922 cache-references                                            
         4,136,614 cache-misses              #   43.466 % of all cache refs    

プログラムAでは、プログラムBの約13.8倍のキャッシュミスが発生していた。 つまりメモリアクセスの回数が13.8倍多いということ。 メモリアクセスがボトルネックとなって、1サイクルあたりの命令実行数にも差が生じていることが分かる。

2014年9月23日火曜日

単語が辞書に存在するかどうかを調べる


 暗号化された英語の文章を復号するという問題に挑戦しています。
復号化された文章が正しい英単語から構成されていることを確認するために、単語が辞書に存在するかどうかをチェックする機能を実装しました。Ubuntuの場合は、/usr/share/dict/american-englishにアメリカ英語の単語リストが存在するので、それを使いました。  
#include <iostream>
#include <fstream>
#include <set>

using namespace std;

class dictionary {
    set<string> container;

public:
    void load(const string &path) {
        ifstream fs(path);

        string word;
        while (fs >> word)
            container.insert(word);
    }

    bool contains(const string &word) {
        return container.count(word);
    }
};


int main(int argc, char **argv) {

    dictionary dict;
    dict.load("/usr/share/dict/american-english");

    for (string s; cin >> s; ) {
        if (dict.contains(s))
            cout << s << " is in the dictionary." << endl;
        else
            cout << s << " is not in the dictionary." << endl;
    }

    return 0;
}
以下実行結果です。固有名詞も辞書に含まれているみたいです。
hello
hello is in the dictionary.
world
world is in the dictionary.
soccer
soccer is in the dictionary.
Linux
Linux is in the dictionary.
Beatles
Beatles is in the dictionary.
Fibonacci
Fibonacci is in the dictionary.
totient
totient is not in the dictionary.
Yankees
Yankees is in the dictionary.

2014年3月6日木曜日

UNIXコマンドメモ

 自分用のメモ書きです。

1. プロセスが使用しているポートを調べる
netstatを使う方法
$ sudo netstat -tanp | grep mysql
-t: TCPのみ
-a: listenしているソケットもしていないソケットも表示
-n: アドレスを数値で表示
-p: プロセス名を表示

lsofを使う方法
$ sudo lsof -c mysql -a -i -a -P
-c: プロセス名を指定
-a: 条件をANDでつなげる(デフォルトはOR結合)
-i: listenしているポートを表示
-P: ポート番号をポート名に変更(80->httpのように)しない

2. ポートを使用しているプロセスを調べる
$ sudo lsof -i:3306

3. ファイルを高速検索する
$ locate httpd.conf
locateはディスク上のファイルではなく、DBに格納されたファイルパス情報を検索している。 DBはupdatedbというコマンドで最新化できる。updatedbはcronに登録されている。

4. 素因数分解する
$ factor 123456789

5. 画像ファイルを表示する
$ display xxx.jpg

6. ファイルからベース名(拡張子を除いたもの)を取得する
$ basename test.cpp .cpp

7. インストールされたライブラリのメタ情報を取得する
$ pkg-config --cflags opencv
$ pkg-config --libs opencv

特定のライブラリに依存するソースコードをコンパイルするときに便利。
以下のようにバッククオート演算子と組み合わせて使う。
$ g++ -ggdb `pkg-config --cflags opencv` -o `basename opencvtest.cpp .cpp` opencvtest.cpp `pkg-config --libs opencv`

8. ファイル、URLをデフォルトのアプリケーションで開く
$ xdg-open sample.avi
$ xdg-open http://yahoo.co.jp
上の例では、それぞれビデオファイル、yahooのページをデフォルトのアプリケーションで開きます。

9. Linuxのバージョンを確認する
$ lsb_release -a

10. インストールされているパッケージのリストを取得する
$ dpkg -l
必要に応じて、パイプとgrepで絞り込みを行う。
$ dpkg -l | grep openssl

11. マシンが32bit/64bitのどちらで動作しているか調べる
CPUが64bitをサポートしているかどうかは以下のコマンドで分かる。
$ lscpu | grep op
CPU op-mode(s): 32-bit, 64-bit のように表示されれば、64bitのオペレーションモードをサポートしていることが分かる。

次に、OSが64bitかどうかは以下のコマンドで分かる。
$ uname -m  # uname -p でもOK.
x86_64のように表示されれば64bit。ix86のように表示されれば32bit。
64bit CPU上で64bit版OSが動作している場合に、マシンは64bit環境で動作していると言う。

2012年12月1日土曜日

Dropboxを入れてみた

最近、競技プログラミングの問題をカテゴライズして、各問題ごとに直近で解いた日時、解いた回数を管理するような簡易アプリを作りました。
特にWEB上に公開するようなつもりは無くて、ローカルPCにApacheを入れてLANからのみ見れるようにしました。

1ヶ月間くらい使ってみて、問題がたまってきたので、バックアップを取りたいなと思いました。で、手軽にできるものが無いかなと考えていたところ、Dropboxを使うと簡単にできそうなのでやってみました。

やりたいこと
  • ローカルPCが壊れても、復旧できるようにしたい。
  • バックアップ対象は、DBのデータとPHPのソース。
  • バックアップの頻度は、3日に1回程度。
やったこと
まず、Dropboxをインストール。
すると、HOMEディレクトリにDropboxというディレクトリができる。
ここにファイルを入れるとDropboxのサーバーに自動で保存されるので、バックアップ完了という流れ。

あとは、自動でDBのdumpと、ソースコードをまとめてtar化するようなスクリプトを書けばいいだけ。
#!/bin/sh

data_backup_file="/home/kenjih/Dropbox/backup/procom/data/dump.sql"
src_backup_file="/home/kenjih/Dropbox/backup/procom/src/app.tar"
src_dir="/home/kenjih/dev/procom/src/app"
log="/home/kenjih/Dropbox/backup/procom/backup.log"

today=`date '+%s'`
updated_date=`stat -c '%y' ${data_backup_file}`
expire_date=`date -d "${updated_date} 3 days" '+%s'`

if [ $today -gt $expire_date ]; then
    mysqldump -u usr -ppasswd procom >${data_backup_file}
    tar -cf ${src_backup_file} ${src_dir} 2>/dev/null
    echo "backup files saved at `date '+%Y/%m/%d %T'`." >>${log}
fi

で、cronを設定。
# m h  dom mon dow   command
0 23 * * * /home/kenjih/dev/procom/src/app/Console/backup.sh

2012年8月22日水曜日

Ubuntu12.04のキーボード設定


"Sunset on Beach Stage"

キーボードの設定を変えました。

HUDの無効化
デフォルトでは、Altキーを押すとHUDが立ち上がります。Altキーを押す度にウィンドウが開いてフォーカスが移り面倒なので、このサイトを参考にHUDを無効化しました。

右Altキーの設定
やっぱり右Altキーは欲しいです。ということで、以下の手順で変換キーを右Altキーに割り当てました。
  1. コマンドラインにxevと入力する。
  2. 変換キーを押すと、変換キーのkeycode(100)が表示される。
  3. ~/.Xmodmapに以下を設定
keycode 100 = Alt_L
add mod1 = Alt_L

2012年8月4日土曜日

Recursive Grep

ソースコードにTODOと書いて、後からTODOと書いている箇所をまとめてgrepしようと思って、
$ grep TODO *
としてみましたが、ヒットせず。
$ grep TODO *
$ grep TODO */*
$ grep TODO */*/*
とかやっていくと出るんですけど、もっと楽にできないかなと思い、
find . -name "*" | grep TODO
とかやってみました。
なぜかヒットせず。。いやこれだとカレントディレクトリ配下にTODOという文字列を含むファイルorサブディレクトリがないか検索してるだけだ。findでヒットしたファイルをgrepの引数として渡してあげる方法はないんだろうか・・・。 ありました。xargsを使えばよさそうです。
find . -name "*" | xargs grep TODO
でやりたいことができました。ちなみにxargsは、extended argumentsの略らしいです。

2011年10月26日水曜日

UNIX環境でサービスのポート番号を調べる方法

教えてもらったので忘れないうちにメモ。

例えば、MySQLのポートを調べたいときは、以下のようにします。

$ sudo lsof -P | grep mysql | grep TCP

 lsofはプロセスによって開かれているファイルの情報を出力するらしいです。ここでいう"ファイル"とは、通常のファイルやディレクトリ、さらにはライブラリ、ストリーム、ネットワークファイルまで含まれます。
-Pオプションは、ポート番号をポートの名前(サービス名)に変換するのを抑制するという意味です。-Pオプションを付けない場合は

TCP *:mysql (LISTEN)

と表示されるのが、-Pをつけると、

TCP *:1234 (LISTEN)

のようにポートの番号で表示されます。

ちょっと調べてみたところ、-iオプションというものもあって、これを使うとネットワーク関連の情報だけを取り出せます。上のコマンドは以下のようにしてもいいです。

$ sudo lsof -i tcp | grep mysql

 lsofの他にも、socklistというコマンドがあるみたい。このコマンドはオプションなしで

$ sudo socklist

とすると、lsofと同様に通信プロトコル、ポート番号、プロセスID、サービス名などが表示されます。こっちの方が楽ですねー。



2011年10月21日金曜日

sedの最短一致

最近知ったけど、sedはstream editorの略らしい。
それはどうでもよくて、sedの正規表現のマッチングの小技的なものをメモとして書いておく。
HTMLをパースする場合を考える。
 
 例えば、

<tr><td>id</td><td>data</td></tr><tr><td>1</td><td>AKB48</td></tr><tr><td>2</td><td>perfume</td></tr><tr><td>3</td><td>bump.y</td></tr>
…

のようなデータからHTMLのタグだけを消して、意味のある値だけを取り出したいとする。つまり、

id data
1 AKB48
2 perfume
3 bump.y
…

のような出力をえたい。

 このときに、
sed s/\<.*\>//g test.html
みたいな書き方をすると悲しいことになる。(行全体にマッチしてしまい、すべて空行になってしまう。)
これは、複数のマッチングが考えられる場合なるべく長いものにマッチする(最長一致)からである。この性質はsedに限ったことではなくて正規表現全般に言えることで、デフォルトでは最長一致である。

 最短一致を利用するためのオプションを持つ言語もあるが、sedには無いので何らかの工夫が必要となる。今回の場合は、閉括弧が現れた時点で一旦マッチングをやめるようにすればいいので、以下のように書くと思惑のデータがえられる。

sed s/\<[^\>]*\>//g test.html

 データの間にスペースを入れたい場合は、
sed 's/<[^>]*>/ /g' test.dat
とする。(スペースを用いるので''で第一引数を囲む。''を使うとエスケープ文字の扱いが変わるので<>はエスケープしない。※注)

※注)
 シングルクオーテーションで囲んだ場合、シングルクオーテーション以外の文字は普通の文字と同じ扱い。ダブルクオーテーションで囲んだ場合は、"$`\以外の文字は普通の文字と同じ扱いになるそうです。

2011年10月17日月曜日

Visualize Apache Log on Google Map

I'm lately playing by mapping Apache log on Google Map. This is it, named Access Visualizer. (I recommend you see it with Google Chrome. Some browsers cannot handle some features in the app.)

If you put your mouse cursor on a marker, you can see the next information:
  • ISP
  • Organization
  • Country
  • Region
  • Coordinate (latitude, longitude)
I used a witty service that can convert IP addresses into location information. And this service allows you to use their functionality by API (XML-based REST).

What I did to create the app is:
  1. consider the DB structures and create DB tables.
  2. write a shell script and some PHP scripts to parse Apache log, run queries, and store the data into MySQL database.
  3. write a PHP script that automatically generate Javascript code which utilize Google Map API.
Not so difficult tasks. Let's go deeper into each section.
1. is an interesting part. Since the query number is limited to 100 times a day, I think it's good to store IP-location data into my own database so that I can re-use the same queries previously used. In the current IP address scheme, there's 2^32 IP addresses, which is about 4*10^9 in decimal. But an organization has a several, or hundreds of global IP addresses. So considering an efficient database table structure is interesting!

2. is kind of tedious. Just wrote a shell script and PHP scripts.

3. is the first time for me to use Google Map API. I actually tried to use the API before, but I gave up it since the use was restricted and some registration was needed at the time. But now its version is updated, and now, you can utilize their APIs without any registration and restriction!! Yikes, thanks Google!!

The future trials:
With lots of markers, there are some parts you cannot see. Japan is hidden and unseen due to the markers now lol So I'm considering to create some layers that control whether show a marker or not. Some markers are to be unseen when zoom-out, but be seen when zoom-in.
Plus, public location information about IP is not so accurate unfortunately . For example, KDDI, University of Tokyo and other organizations are located in the exactly same point according to utrace. Due to this, you cannot see the marker for University of Tokyo and KDDI. I have to scatter the points at the exactly same point in some manner.

2011年10月8日土曜日

apacheのログを見て遊ぶ

最近、apacheのログの見方が分かるようになりました。いろいろ整形して遊んでみると面白いです。デフォルトでは、/var/log/apache2にログが吐かれます。まだ基本的なことしかできないですが、一応まとめ。

1. 直近のアクセスログを見る
tail access.log

2. 自分のローカルマシン以外のアクセスログを見る(自分のマシンのIPがxx.xx.xx.xxの場合)
grep -v xx.xx.xx.xx access.log

3. ユニークユーザー数を見る
cat access.log | awk '{print $1}' | sort | uniq | wc -l

4. アクセス元を訪問数の多い順にソートして表示する
cat access.log | awk '{print $1}' | sort | uniq -c | sort -r

5. リファラー(どこからこのページにやってきたか)を多い順にソートして表示する
cat access.log | awk '{print $11}' | sort | uniq -c | sort -r

4., 5. で$1、$11などと書きましたが、これはapacheの設定によって違うので、自分の環境にあわせて適当に変えてください。
あと、IPから場所を特定できるサイトがあるので、これと組み合わせるとおもしろいです。Google Analyticsだと都市名までしか出てきませんが、このサービスを使うと、大学名や企業名まで分かります。有名な海外大学からアクセスがあったりするとテンションがあがります。このサイトからは、APIが公開されていてHTTPでxmlデータを取り込むことができます。非商用のクエリは100件まで無料ということです。アクセス元のIDをためていって、適当なタイミングでAPIを流すようにして、アクセス元IP - 場所の対応データを溜めていくのもおもしろいかもしれません。

2011年5月5日木曜日

Emacs 入門(5)

Emacs上でShellを使用する方法、設定についてメモ書き。

Emacs上でShellを使用する方法は主に以下3つがある。
  1. Emacs::shell
  2. Emacs::eshell
  3. Emacs::ansi-term

1. 一番よく使われるemacs上のシェル。M-x shellで起動。
ちょっと癖があるのは、1つ前のコマンドを参照するときは「M-p」、1つ次のコマンドを参照するときは「M-n」と入力する。あと頻繁に文字化けする。

2. lispを使用したシェル。M-x eshellで起動。起動に時間がかかる。

3. M-x ansi-termで起動。今日初めて使ったけど、3つの中では最強な気がする。ほぼ普通のshellな気がする。

ということで、3.のansi-termを使うことにしよう。