プログラミングメモ帳

プログラミングで躓いた部分を中心としたIT土方的メモ。

Log4j2 で日付ベースのログローテーション

Log4j2 で吐いたログに対して日付ベースでのログローテーションと時限削除をしたいとき、
logrorated 等のローテーション管理ソフトウェアに任せると、Log4j2 側がファイルを見失ってしまうので、ローテーションを Log4j2 側で実現してやる。

<Appenders>
    <RollingFile name="hoge" fileName="logs/hoge.log" filePattern="logs/hoge.%d{yyyy-MM-dd}.log">
        <PatternLayout pattern="%m%n" />
        <TimeBasedTriggeringPolicy />
        <DefaultRolloverStrategy>
            <Delete basePath="logs" maxDepth="1">
                <IfFileName glob="hoge*.log" />
                <IfLastModified age="7d" />
            </Delete>
        </DefaultRolloverStrategy>
    </RollingFile>
</Appenders>

DefaultRolloverStrategy の min, max は 日付ベースのローテーションに対して効かないので、
自分で Delete タグを使って削除をする必要がある。

単純に日付ベースで古いファイルを分けたいだけなら、特に何も考えず TimeBasedTriggeringPolicy すればよい。

参考

[LOG4J2-435] Feature request: auto-delete older log files - ASF JIRA

ELB 配下に Django アプリケーションを置く時の ALLOWED_HOSTS 設定

Django では settings.py の ALLOWED_HOSTS で指定したホスト名でのみアクセスを受け付けられる。
(確認してないけど、たぶん HTTP リクエストヘッダの Host を見ているとかだと思う)

なので、ここにユーザからアクセスされる際に使われるドメイン名を書いておくのだが、
AWS の Elastic Load Balancer (の Application/Classic Load Balancer) 配下に置き、
かつヘルスチェックの判定条件を「アプリケーションが 200 OK を返す」形で設定する場合は、
以下のような設定が必要になった。

続きを読む

ModelFormを利用して生成されるHTMLフォーム内の要素のnameタグを変更する

Django で Model を利用して入力画面を作る際には ModelForm クラスを利用しますが、
Model のフィールド名と、投げられるリクエストの名前規則が一致しないことがあります。

リクエストを投げる側の動作を変更したくない(できない)場合、以下のように、ModelFormクラス内のadd_prefix()をオーバライドすることで、フォーム内の要素の name 属性の値を変更することが出来ます。


FIELD_NAME_MAPPING = {
    # 'Modelクラスのフィールド名' : 'name属性の値'
    'field1': 'html_field1',
    'field2': 'html_field2'
}

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel
        fields = '__all__'

    def add_prefix(self, field_name):
        field_name = FIELD_NAME_MAPPING.get(field_name, field_name) # dict に存在しない場合はフィールド名を利用する
        return super(MyForm, self).add_prefix(field_name)


この add_prefix()メソッドですが、元々の動作はメソッド名の通り、 name 属性に設定されるフィールド名全てに接頭辞を与えるというものです。 この使い方の場合は、ModelForm のフィールドとして prefix = 'hoge' のように与えてやれば良いみたいです。
name 属性に設定する値をまるごと返す設計になっているので、Model クラスのフィールド名に縛られず自由に書き換えることができます。


参考

stackoverflow.com

https://docs.djangoproject.com/ja/1.11/_modules/django/forms/forms/docs.djangoproject.com

argparseでハイフン入りオプションを使う

前略、pythonのargparseは非常に便利です。

add_argument()の第一引数 name に対して--fooのような文字列を与えてやると、parse_args()で得られるオブジェクトに対して.fooでアクセスし値を取ってこれる、という便利な実装になっています。 具体的にはこういう感じになります。

if __name__ == '__main__':
  parser = argparse.ArgumentParser(description=u'サンプル')
  parser.add_argument("--foo")
  args = parser.parse_args()
  
  if args.foo':
    print 'これで取れる'

ただ、一つだけよくわからないことがあります。 これ、nameにハイフンが含まれた時どうすんの?

というわけで実験しました。

if __name__ == '__main__':
  parser = argparse.ArgumentParser(description=u'サンプル')
  parser.add_argument("--hoge-fuga")
  args = parser.parse_args()
  
  if args.hoge_fuga':
    print 'これで取れる'

上記のように、--hoge-fugaというオプションは.hoge_fugaとしてアクセスが可能です。 ハイフンは自動でアンダースコアに置換されるようです。

XmlSlurper の出力時に tag0 名前空間が付かないようにする

XmlSlurper クラスを利用して XML ドキュメントを読み込んだあと、 いろいろ処理をしたあとに書き出してみたら <tag0:xxx> という名前空間になってしまって困る場合の対処法。

import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil

def doc = new XmlSlurper(false, false).parse(new File('input.xml'))

// 色々処理する

def out = new FileWriter('output.xml')
XmlUtil.serialize(new StreamingMarkupBuilder().bind {
    mkp.yield doc
}, out)

コンストラクタ XmlSlurper() の第 2 引数に false を指定すると、tag0 名前空間が与えられるのを阻止できる。
(ちなみに第 1 引数は XML 文章の検証を行うかどうかを設定できるもので、引数なしの場合は false になる)

参考: XmlSlurper (Groovy 2.4.12)

paint/paintComponentが呼ばれてないぞ?と思ったら

オーバーライドするとき、super() の呼び忘れがないかを確認する。

public class TestJPanel extends JPanel {
    
    public TestJPanel() {
        setBackground(Color.cyan);
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g); // 背景を描く
        g.drawLine(50, 50, 200, 200); // 線を描く
        g.drawLine(200, 50, 50, 200); // 線を描く
        g.drawRect(50, 50, 150, 150); // 四角を描く
        }
    }
}

のように、paintComponent()に描画処理を書いてしまって、paint()メソッドをオーバーライドしないようにする。

JPanelクラスのpaint()メソッドは内部でpaintComponent()を呼んでいるので、自分で手を加えると正常に動作しなくなる場合がある。

ImportError: No module named PyQt4

brew install pyqt

をしたあとに

import PyQt4

をしたら

ImportError: No module named PyQt4

と怒られてしまったときのメモ。

export PYTHONPATH=/usr/local/lib/python2.7/site-packages:$PYTHONPATH

を.bashrcもしくは.bash_profileに追加すればOK。

$ python
>>>import sys
>>>sys.path

してみて、どばーっと出てきたパスの中に'/usr/local/lib/python2.7/site-packages'があればOK。ダメなら.bashrcがちゃんと読み込めているか見直してみる。

この状態なら正常にimport出来るはず。