コピペコードで快適生活

明日使えるソースを自分のために

unicornのlogrotate設定サンプル

/etc/logrotate.d 配下に下記を置く。
日次ローテート + 90日間保存で設定しています。
ローテートしたログは圧縮するが、直近の1世代分はそのまま

/var/www/app/shared/log/*.log {
  daily
  missingok
  rotate 90
  dateext

  compress
  delaycompress

  lastaction
    pid=/var/www/app/shared/tmp/pids/unicorn.pid
    test -s $pid && kill -USR1 "$(cat $pid)"
  endscript
}

※メモ
Unicornには、USR1シグナルを送ると、ログファイルを開きなおす機能が備わっている。
そのため、現在のログをリネームした後、USR1シグナルを送信してログをローテートする。

serviceコマンドでunicorn起動するための設定サンプル

下記ファイル を /etc/init.d/ に配置する。

#!/bin/sh
# chkconfig: 345 99 01
# description: unicorn as Rails app server

SERVICE="unicorn"
ENV="production"

RAILS_ROOT="/var/www/app/current"
CONFIG=$RAILS_ROOT"/config/unicorn/"$ENV".rb"
PID_FILE=$RAILS_ROOT"/tmp/pids/unicorn.pid"

start() {
    START_CMD="cd $RAILS_ROOT && (RAILS_ENV=$ENV /usr/bin/env bundle exec unicorn -c $CONFIG -E $ENV -D)"
    su -l $USER -c "$START_CMD" &
    echo "service $SERVICE [start]"
}

stop() {
    STOP_CMD="cd $RAILS_ROOT && /usr/bin/env kill -s QUIT `cat $PID_FILE`"
    su -l $USER -c "$STOP_CMD" &
    echo "service $SERVICE [stop]"
}

status() {
    PID=`pgrep -f $CONFIG | wc -l`
    if [ $PID -eq 0 ]; then
        echo "$SERVICE stop"
    else
        echo "running $SERVICE ..."
    fi
}


case $1 in
start)
    start
    ;;
stop)
    stop
    ;;
restart)
    stop
    start
    ;;
status)
    status
    ;;
*)
    echo "Usage: $SERVICE [start|stop|restart|status]"
    ;;
esac
exit 0

下記コマンドで service に登録する

# /etc/init.d
# sudo chkconfig --add unicorn

使い方

# sudo service unicorn [start|stop|restart|status]

webpack+Reactの環境構築メモ

npm install

$ cd my_project
$ npm init
$ npm install webpack -g
$ npm install --save react react-dom
$ npm install --save-dev webpack webpack-dev-server
$ npm install --save-dev babel-loader babel-core babel-preset-react babel-preset-es2015

ReactDOM
DOM に React 要素をレンダーするためのモジュール

webpack
複数のファイルを変換してまとめるツール
たとえば複数のjsを変換してひとつにまとめたり。

babel (babel-cor)
JSコードの変換ツール

babel-loader
bableをwebpackで使うためのライブラリ

babel-preset-react
jsxをjsに変換するためのpreset(JSXはReact.createElementの糖衣構文)

babel-preset-es2015
ES2015をES5に変換するためのpreset


webpack.config.js

const webpack = require("webpack");

module.exports = {
  // minify
  // plugins: [
  //   new webpack.optimize.UglifyJsPlugin()
  // ],

  context: __dirname + '/src',

  entry: {
    js: './js/index.js'
  },

  output: {
    path: __dirname + '/dist',
    filename: './js/app.js'
  },

  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015']
        }
      },
      {
        test: /\.jsx$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015', 'react']
        }
      }
    ]
  },

  devServer: {
    // contentBase: 'dist',
    host: '127.0.0.1',
    port: 8080
  },
};

ビルド

webpack

開発サーバ起動
package.jsonのscriptsに

 "start": "webpack-dev-server"

追加して

npm run start

参考
http://uraway.hatenablog.com/entry/2015/12/25/Webpack_%2B_React_%2B_ES6%E3%81%AE%E6%9C%80%E5%B0%8F%E6%A7%8B%E6%88%90%E3%82%92%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B%E3%80%82

http://dackdive.hateblo.jp/entry/2016/04/13/123000#webpackconfigjs-の例

http://dackdive.hateblo.jp/entry/2016/05/07/183335

Elasticsearchことはじめ

仕事でElasticsearch使う必要があったので、GettingStarted!

これはなに?

分散型RESTful検索/分析エンジン
https://www.elastic.co/jp/products/elasticsearch

特徴

  • 速い
  • スケールが容易(クラスタ構成)
  • RESTful APIで全ての入出力が可能

検索時は条件との完全一致ではなく"関連性が高いもの"を返す
http://gihyo.jp/dev/serial/01/js-foundation/0008

RDBとの用語対応表

ElasticSearch
Index > MappingType > Document

RDB
database > Table > record

インストール

rpm -ivh https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.2.1.rpm
chkconfig --add elasticsearch
service elasticsearch start

基本操作

https://www.elastic.co/guide/en/elasticsearch/reference/5.2/getting-started.html

起動確認
curl -X GET http://localhost:9200
{
  "name" : "Ovee1U6",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "_-CFvUxgRFy_4Q4lwKWMjw",
  "version" : {
    "number" : "5.2.1",
    "build_hash" : "db0d481",
    "build_date" : "2017-02-09T22:05:32.386Z",
    "build_snapshot" : false,
    "lucene_version" : "6.4.1"
  },
  "tagline" : "You Know, for Search"
}
インデックスの登録
curl -X PUT http://localhost:9200/customer?pretty
{
  "acknowledged" : true,
  "shards_acknowledged" : true
}
インデックス一覧
curl -X GET http://localhost:9200/_cat/indices?v
health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   customer nXJXYUdyRpG_yxh-qTp7_w   5   1          0            0       650b           650b
ドキュメント登録
curl -X PUT http://localhost:9200/customer/external/1?pretty -d '
{
  "name": "John Doe"
}
'

インデックス/タイプが未作成の場合は一緒に作成される。
ID未指定の場合はPOSTメソッドを指定する。

ドキュメント確認
curl -X GET http://localhost:9200/customer/external/1
{
  "name": "John Doe"
}
インデックス削除
curl -X DELETE http://localhost:9200/customer?pretty
{
  "acknowledged" : true
}

更新操作

変更
curl -X POST http://localhost:9200/customer/external/1/_update?pretty -d '
{
  "doc": {"age": 20}
}
'

ageカラムがある場合は上書き、ない場合は追加される。
他のカラムに影響はない。
メソッドはPUTではなくPOSTなのに注意。

スクリプト使った変更
curl -X GET http://localhost:9200/customer/external/1?pretty -d '
{
  "script": "ctx._source.age += 5"
}
'
ドキュメント削除
curl -X DELETE http://localhost:9200/customer/external/1?pretty
一括登録
curl -XPOST 'localhost:9200/customer/external/_bulk?pretty&pretty' -H 'Content-Type: application/json' -d'
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }

検索&集計

テストデータ登録
curl -X POST 'localhost:9200/bank/account/_bulk?pretty&refresh' --data-binary "@accounts.json"
curl http://localhost:9200/_cat/indices?v

サンプルjsonはここから
https://raw.githubusercontent.com/elastic/elasticsearch/master/docs/src/test/resources/accounts.json
ファイル名の前に@をつける必要がある。

書き方1
curl -XGET 'localhost:9200/bank/_search?q=*&sort=account_number:asc&pretty'
{
  "took" : 83,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "bank",
        "_type" : "account",
        "_id" : "0",
        "_score" : null,
        "_source" : {
          "account_number" : 0,
          "balance" : 16623,
          "firstname" : "Bradshaw",
          "lastname" : "Mckenzie",
          "age" : 29,
          "gender" : "F",
          "address" : "244 Columbus Place",
          "employer" : "Euron",
          "email" : "bradshawmckenzie@euron.com",
          "city" : "Hobucken",
          "state" : "CO"
        },
        "sort" : [
          0
        ]
      }, ...
    ]
  }
}

q=* -> すべてを指定
sort=account_number:asc -> ソート指定

書き方2
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" }
  ]
}
'
取得件数指定
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" }
  ],
  "from": 10,
  "size": 10
}
'
取得カラム指定
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}
'
完全一致検索
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": { "match": { "address": "mill" } }
}
'
bool queryを用いた複数条件指定
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "40" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ],
      "filter": {
        "range": {
          "balance": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}
'
集計
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      }
    }
  }
}
'

aggs は aggregations(集計) の略。
SQLでいうとこんな感じ。

SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC
集計(平均値を出す)
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword",
        "order": {
          "average_balance": "desc"
        }
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}
'

ざっとこんな感じで。

JavaScript(ES5)でクラスベースっぽくオブジェクト思考する

JavaScript(ES5)でクラスベースっぽくオブジェクト思考したかったので簡単な書き方をメモ。

var MyObject = function(a){
  // アクセサっぽく
  this.a = a;

  // privateメソッドっぽく
  var privateFunction = function(){
    alert('private function! arg is ' + a);
  }

  // publicメソッドっぽく
  var publicFunction = function() {
    alert('public function! arg is ' + a);
  }
  this.publicFunction = publicFunction;
};


// 使い方
var obj = new MyObject("hoge");
obj.a                 // => "hoge";
obj.a = "fuga";
obj.a                 // => "fuga";
obj.publicFunction(); // => public function! arg is fuga

WindowsでAndroid開発環境を整える

仕事でAndroidアプリを扱うことになったけど、開発環境構築で色々とハマった。同じことを繰り返さないように設定メモを残しておく。

インストール

JDK

ここからダウンロードしてインストールする。
http://www.oracle.com/technetwork/jp/java/javase/downloads/index.html

AndrodiStudio

ここからダウンロードしてインストールする。
https://developer.android.com/studio/index.html

JDKの参照設定

AndroidStudioがJDKを参照できるように設定する。

環境変数

JAVA_HOME に jdkのインストールディレクトリを設定。
 (例: C:\Program Files\Java\jdk1.8.0_112)

・PATH に jdkインストールディレクトリ直下のbin を設定。
 (例: C:\Program Files\Java\jdk1.8.0_112\bin)

AndroidStudioのJDK Location

File -> Project Structureを開いて SDK LocationのJDK location に JDKのインストールディレクトリを設定。

Gitの設定

AndroidStudioは内部でgitコマンドを打つっぽい。コマンドプロンプトでgitコマンドが使えるように設定する。Cygwinっ子の僕はこんな感じで。
http://kinosuke.hatenablog.jp/entry/2016/12/02/151109

開発チュートリアル

Googleから初心者向けのチュートリアルが公開されている。ありがたい。
https://developer.android.com/training/basics/firstapp/index.html

AARファイルの作り方&取り込み方

Googleにドキュメントがある。ありがたい。
https://developer.android.com/studio/projects/android-library.html

なお、AARファイルを取り込むときに modules:aarファイル名 とすると、modulesディレクトリの下にモジュールが保存されるみたい。

実機テスト

こちらをご参考に。
https://blog.codecamp.jp/android_test

コマンドプロンプトでCygwinのシェルを使う

DLLコピー

C:\app\cygwin\bin\cygwin1.dll

C:\Windows\System32

配下にコピーする。

環境変数設定

システム環境変数のPATHに下記を追加。

C:\app\cygwin\bin
C:\app\cygwin\usr\bin
C:\app\cygwin\usr\local\bin

最後に

再度ログインする。これで使える。

CygwinはC:\app\以下にインストールされている前提。
※参照:http://news.mynavi.jp/articles/2013/11/25/zerokaracygwin/